xo-interpreter2 stack: refactor + bugfix operator expr

This commit is contained in:
Roland Conybeare 2026-03-12 20:26:08 -05:00
commit 9c17e89bf0
51 changed files with 572 additions and 505 deletions

View file

@ -103,11 +103,11 @@ add_subdirectory(xo-stringtable2) # experiment w/ facet object model
add_subdirectory(xo-gc) # experiment w/ facet object model
add_subdirectory(xo-object)
add_subdirectory(xo-object2) # experiment w/ facet object model
add_subdirectory(xo-type) # experiment w/ fomo
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-type) # experiment w/ (fomo)
add_subdirectory(xo-tokenizer2) # schematika tokenizer (fomo)
add_subdirectory(xo-expression2) # schematika expressions (fomo)
add_subdirectory(xo-reader2) # schematika expression parser (fomo)

View file

@ -58,9 +58,14 @@ namespace xo {
* Return false if installation fails (e.g. memory exhausted)
**/
virtual bool install_type(Opaque d, const AGCObject & iface) = 0;
/** add gc root with address @p p_root **/
virtual void add_gc_root_poly(Opaque d, obj<AGCObject> * p_root) = 0;
//virtual void add_gc_root_typed(Opaque d, typeseq tseq, Opaque * root) = 0;
/** remove gc root with address @p p_root **/
virtual void remove_gc_root_poly(Opaque d, obj<AGCObject> * p_root) = 0;
/** Request immediate collection.
* 1. if collection is enabled, immediately collect all generations
* up to (but not including) g

View file

@ -39,6 +39,7 @@ namespace xo {
// non-const methods
[[noreturn]] bool install_type(Opaque, const AGCObject &) noexcept override { _fatal(); }
[[noreturn]] void add_gc_root_poly(Opaque, obj<AGCObject> *) override { _fatal(); }
[[noreturn]] void remove_gc_root_poly(Opaque, obj<AGCObject> *) override { _fatal(); }
[[noreturn]] void request_gc(Opaque, generation) override { _fatal(); }
[[noreturn]] void forward_inplace(Opaque, AGCObject *, void **) override { _fatal(); }

View file

@ -53,6 +53,9 @@ namespace xo {
void add_gc_root_poly(Opaque d, obj<AGCObject> * p_root) override {
I::add_gc_root_poly(_dcast(d), p_root);
}
void remove_gc_root_poly(Opaque d, obj<AGCObject> * p_root) override {
I::remove_gc_root_poly(_dcast(d), p_root);
}
void request_gc(Opaque d, generation upto) override {
I::request_gc(_dcast(d), upto);
}

View file

@ -22,6 +22,9 @@ namespace xo {
RCollector() = default;
RCollector(DataPtr data) : Object{std::move(data)} {}
RCollector(const ACollector * iface, void * data)
requires std::is_same_v<typename Object::DataType, xo::facet::DVariantPlaceholder>
: Object(iface, data) {}
/** forward op in place. Defined in GCObject.hpp to avoid #include cycle **/
template <typename DRepr>
@ -33,6 +36,11 @@ namespace xo {
template <typename DRepr>
void forward_inplace(DRepr ** pp_repr);
/** convenience template where pointer requires pivot **/
template <typename AFacet, typename DRepr>
requires (!std::is_same_v<AFacet, AGCObject>)
void forward_pivot_inplace(obj<AFacet,DRepr> * p_obj);
int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); }
size_type allocated(generation g, role r) const noexcept { return O::iface()->allocated(O::data(), g, r); }
size_type reserved(generation g, role r) const noexcept { return O::iface()->reserved(O::data(), g, r); }
@ -41,6 +49,7 @@ namespace xo {
bool install_type(const AGCObject & iface) { return O::iface()->install_type(O::data(), iface); }
void add_gc_root_poly(obj<AGCObject> * p_root) { O::iface()->add_gc_root_poly(O::data(), p_root); }
void remove_gc_root_poly(obj<AGCObject> * p_root) { O::iface()->remove_gc_root_poly(O::data(), p_root); }
void request_gc(generation g) { O::iface()->request_gc(O::data(), g); }
void forward_inplace(AGCObject * lhs_iface, void ** lhs_data) { O::iface()->forward_inplace(O::data(), lhs_iface, lhs_data); }
@ -50,6 +59,12 @@ namespace xo {
O::iface()->add_gc_root_poly(O::data(), (obj<AGCObject> *)p_root);
}
/** remove root @p p_root **/
template <typename DRepr>
void remove_gc_root(obj<AGCObject, DRepr> * p_root) {
O::iface()->remove_gc_root_poly(O::data(), (obj<AGCObject> *)p_root);
}
static bool _valid;
};

View file

@ -10,6 +10,8 @@
#pragma once
#include <xo/facet/FacetRegistry.hpp>
namespace xo {
namespace mm {
/** defined here to avoid #include cycle, since
@ -34,6 +36,16 @@ namespace xo {
this->forward_inplace(&iface, (void **)p_repr);
}
template <typename Object>
template <typename AFacet, typename DRepr>
requires (!std::is_same_v<AFacet, AGCObject>)
void
RCollector<Object>::forward_pivot_inplace(obj<AFacet, DRepr> * p_objs)
{
auto e = xo::facet::FacetRegistry::instance().variant<AGCObject,AFacet>(*p_objs);
this->forward_inplace(e.iface(), (void **)&(p_objs->data_));
}
}
}

View file

@ -1,4 +1,6 @@
/** @file CollectorTypeRegistry.cpp
*
* @author Roland Conybeare, Mar 2026
**/
#include "CollectorTypeRegistry.hpp"

View file

@ -92,7 +92,7 @@ namespace ut {
REQUIRE(ok);
// wrap primitive as GCObject, then as expression
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(&NumericPrimitives::s_mul_gco_gco_pm);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(NumericPrimitives::make_multiply_pm(alloc));
obj<AExpression,DConstant> fn_expr = DConstant::make(alloc, prim_gco);
REQUIRE(fn_expr.data() != nullptr);
@ -131,7 +131,8 @@ namespace ut {
bool ok = CollectorTypeRegistry::instance().install_types(coll);
REQUIRE(ok);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(&NumericPrimitives::s_mul_gco_gco_pm);
obj<AGCObject> prim_gco
= with_facet<AGCObject>::mkobj(NumericPrimitives::make_multiply_pm(alloc));
obj<AExpression,DConstant> fn_expr = DConstant::make(alloc, prim_gco);
obj<AGCObject> val1 = DFloat::box<AGCObject>(alloc, 3.0);
@ -166,7 +167,7 @@ namespace ut {
bool ok = CollectorTypeRegistry::instance().install_types(coll);
REQUIRE(ok);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(&NumericPrimitives::s_mul_gco_gco_pm);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(NumericPrimitives::make_multiply_pm(alloc));
obj<AExpression,DConstant> fn_expr = DConstant::make(alloc, prim_gco);
obj<AGCObject> val1 = DFloat::box<AGCObject>(alloc, 3.0);
@ -201,7 +202,7 @@ namespace ut {
bool ok = CollectorTypeRegistry::instance().install_types(coll);
REQUIRE(ok);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(&NumericPrimitives::s_mul_gco_gco_pm);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(NumericPrimitives::make_multiply_pm(alloc));
obj<AExpression,DConstant> fn_expr = DConstant::make(alloc, prim_gco);
obj<AGCObject> val1 = DFloat::box<AGCObject>(alloc, 3.0);
@ -283,7 +284,8 @@ namespace ut {
bool ok = CollectorTypeRegistry::instance().install_types(coll);
REQUIRE(ok);
obj<AGCObject> prim_gco = with_facet<AGCObject>::mkobj(&NumericPrimitives::s_mul_gco_gco_pm);
obj<AGCObject> prim_gco
= with_facet<AGCObject>::mkobj(NumericPrimitives::make_multiply_pm(alloc));
obj<AExpression,DConstant> fn_expr = DConstant::make(alloc, prim_gco);
obj<AGCObject> val1 = DFloat::box<AGCObject>(alloc, 3.0);

View file

@ -9,7 +9,6 @@
#include "TypeRegistry.hpp"
#include "facet_implementation.hpp"
//#include "typeseq.hpp"
#include "obj.hpp"
#include <xo/arena/DArenaHashMap.hpp>
#include <xo/indentlog/scope.hpp>

View file

@ -273,7 +273,7 @@ namespace xo {
*
* Deliberately disable this for variants
**/
DRepr * operator->()
DRepr * operator->() const noexcept
requires (!std::is_same_v<DataType, DVariantPlaceholder>)
{ return data_; }

View file

@ -47,6 +47,7 @@ namespace xo {
static bool install_type(DX1Collector & d, const AGCObject & iface);
static void add_gc_root_poly(DX1Collector & d, obj<AGCObject> * p_root);
static void remove_gc_root_poly(DX1Collector & d, obj<AGCObject> * p_root);
static void request_gc(DX1Collector & d, generation upto);
static void forward_inplace(DX1Collector & d, AGCObject * lhs_iface, void ** lhs_data);

View file

@ -287,6 +287,14 @@ namespace xo {
*(obj<AGCObject> **)mem = p_root;
}
void
DX1Collector::remove_gc_root_poly(obj<AGCObject> * p_root) noexcept
{
// iterate over roots_, find p_root and drop it
(void)p_root;
}
void
DX1Collector::request_gc(generation upto) noexcept
{

View file

@ -67,6 +67,13 @@ namespace xo {
d.add_gc_root_poly(p_root);
}
void
ICollector_DX1Collector::remove_gc_root_poly(DX1Collector & d,
obj<AGCObject> * p_root)
{
d.remove_gc_root_poly(p_root);
}
void
ICollector_DX1Collector::request_gc(DX1Collector & d,
generation upto)

View file

@ -161,24 +161,6 @@ xo_add_genfacetimpl(
# ----------------------------------------------------------------
# note: manual target; generated code committed to git
xo_add_genfacetimpl(
TARGET xo-interpreter2-facetimpl-gcobject-globalenv
FACET_PKG xo_alloc2
# REPR GlobalEnv
INPUT idl/IGCObject_DGlobalEnv.json5
)
# note: manual target; generated code committed to git
xo_add_genfacetimpl(
TARGET xo-interpreter2-facetimpl-printable-globalenv
FACET_PKG xo_printable2
# REPR GlobalEnv
INPUT idl/IPrintable_DGlobalEnv.json5
)
# ----------------------------------------------------------------
# note: manual target; generated code committed to git
xo_add_genfacetimpl(
TARGET xo-interpreter2-facetimpl-gcobject-localenv

View file

@ -36,10 +36,6 @@ set(SELF_SRCS
IGCObject_DClosure.cpp
IPrintable_DClosure.cpp
DGlobalEnv.cpp
IGCObject_DGlobalEnv.cpp
IPrintable_DGlobalEnv.cpp
DLocalEnv.cpp
IGCObject_DLocalEnv.cpp
IPrintable_DLocalEnv.cpp

View file

@ -27,6 +27,8 @@ namespace xo {
InitEvidence
InitSubsys<S_interpreter2_tag>::require()
{
scope log(XO_DEBUG(true));
InitEvidence retval;
/* direct subsystem deps for xo-interpreter2/ */

View file

@ -63,12 +63,7 @@ namespace xo {
FacetRegistry::register_impl<AGCObject, DVsmSeqContFrame>();
FacetRegistry::register_impl<APrintable, DVsmSeqContFrame>();
// GlobalEnv
FacetRegistry::register_impl<AGCObject, DGlobalEnv>();
FacetRegistry::register_impl<APrintable, DGlobalEnv>();
// LocalEnv
// LocalEnv (see xo-reader2/ for GlobalEnv)
FacetRegistry::register_impl<AGCObject, DLocalEnv>();
FacetRegistry::register_impl<APrintable, DLocalEnv>();

View file

@ -110,13 +110,15 @@ namespace xo {
//using X1CollectorConfig = xo::mm::X1CollectorConfig;
//using DArena = xo::mm::DArena;
//using ArenaConfig = xo::mm::ArenaConfig;
using VsmConfig = xo::scm::VsmConfig;
using Replxx = replxx::Replxx;
using span_type = VirtualSchematikaMachine::span_type;
App(const AppConfig & cfg = AppConfig())
: repl_config_{cfg.repl_config_},
app_arena_{cfg.app_arena_config_},
vsm_{cfg.vsm_config_, obj<AAllocator,DArena>(&app_arena_)}
vsm_config_{cfg.vsm_config_}
//vsm_{cfg.vsm_config_, obj<AAllocator,DArena>(&app_arena_)}
{
this->interactive_ = isatty(STDIN_FILENO);
@ -148,7 +150,8 @@ namespace xo {
/** arena with same lifetime as this application **/
DArena app_arena_;
/** schematika virtual machine **/
VirtualSchematikaMachine vsm_;
VsmConfig vsm_config_;
std::unique_ptr<VirtualSchematikaMachine> vsm_;
};
void
@ -162,13 +165,16 @@ namespace xo {
void
App::_init()
{
// window to contorl size of registries ends as soon as we init other subsystems
// window to control size of registries ends as soon as we init other subsystems
TypeRegistry::instance(1024);
FacetRegistry::instance(1024);
InitEvidence init_evidence_ = (InitSubsys<S_interpreter2_tag>::require());
Subsystem::initialize_all();
vsm_.reset(new VirtualSchematikaMachine(vsm_config_,
obj<AAllocator,DArena>(&app_arena_)));
}
void
@ -176,7 +182,7 @@ namespace xo {
{
welcome(cerr);
vsm_.begin_interactive_session();
vsm_->begin_interactive_session();
}
void
@ -186,7 +192,7 @@ namespace xo {
span_type input;
// outer loop: fetch one line of interactive input
while (replxx_getline(interactive_, vsm_.is_at_toplevel(), rx_, &input)) {
while (replxx_getline(interactive_, vsm_->is_at_toplevel(), rx_, &input)) {
// inner loop: consume up to one expression at a time.
while (!input.empty() && this->_read_eval_print(&input, false /*eof*/))
@ -218,7 +224,7 @@ namespace xo {
if (!p_input || p_input->empty())
return true;
VsmResultExt res = vsm_.read_eval_print(*p_input, eof);
VsmResultExt res = vsm_->read_eval_print(*p_input, eof);
*p_input = res.remaining_;

View file

@ -14,21 +14,25 @@ namespace xo {
**/
class NumericPrimitives {
public:
/** polymorphic (in both arguments) multiply **/
static DPrimitive_gco_2_gco_gco s_mul_gco_gco_pm;
using AAllocator = xo::mm::AAllocator;
public:
/** polymorphic (in both arguments1) multiply **/
static DPrimitive_gco_2_gco_gco * make_multiply_pm(obj<AAllocator> mm);
/** polymorphic (in both arguments) divide **/
static DPrimitive_gco_2_gco_gco s_div_gco_gco_pm;
static DPrimitive_gco_2_gco_gco * make_divide_pm(obj<AAllocator> mm);
/** polymorphic (in both arguments) add **/
static DPrimitive_gco_2_gco_gco s_add_gco_gco_pm;
static DPrimitive_gco_2_gco_gco * make_add_pm(obj<AAllocator> mm);
/** polymorphic (in both arguments) subtract **/
static DPrimitive_gco_2_gco_gco s_sub_gco_gco_pm;
static DPrimitive_gco_2_gco_gco * make_subtract_pm(obj<AAllocator> mm);
/** polymorphic (in both arguments) compare (==) **/
static DPrimitive_gco_2_gco_gco s_cmpeq_gco_gco_pm;
static DPrimitive_gco_2_gco_gco * make_cmpeq_pm(obj<AAllocator> mm);
/** polymorphic (in both arguments) compare (!=) **/
static DPrimitive_gco_2_gco_gco s_cmpne_gco_gco_pm;
static DPrimitive_gco_2_gco_gco * make_cmpne_pm(obj<AAllocator> mm);
/** polymorphic (in both arguments) compare (<) **/
static DPrimitive_gco_2_gco_gco s_cmplt_gco_gco_pm;
static DPrimitive_gco_2_gco_gco * make_cmplt_pm(obj<AAllocator> mm);
};
}
}

View file

@ -0,0 +1,20 @@
/** @file numeric_register_primitives.hpp
*
* @author Roland Conybeare, Mar 2026
**/
#pragma once
#include "PrimitiveRegistry.hpp"
#include <xo/alloc2/Collector.hpp>
namespace xo {
namespace scm {
/** Register gc-aware (AGCObject,DRepr) combinations with garbage collector @p gc **/
bool numeric_register_primitives(obj<xo::mm::AAllocator> gc,
InstallSink sink,
InstallFlags flags);
}
}
/* end numeric_register_primitives.hpp */

View file

@ -4,6 +4,7 @@ set(SELF_LIB xo_numeric)
set(SELF_SRCS
init_numeric.cpp
numeric_register_facets.cpp
numeric_register_primitives.cpp
NumericPrimitives.cpp
NumericDispatch.cpp
INumeric_Any.cpp

View file

@ -7,38 +7,59 @@
#include "NumericDispatch.hpp"
namespace xo {
using xo::mm::AGCObject;
using xo::mm::AAllocator;
//using xo::mm::AGCObject;
namespace scm {
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_mul_gco_gco_pm("_mul",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_multiply_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_mul",
&NumericDispatch::multiply);
}
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_div_gco_gco_pm("_div",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_divide_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_div",
&NumericDispatch::divide);
}
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_add_gco_gco_pm("_add",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_add_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_add",
&NumericDispatch::add);
}
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_sub_gco_gco_pm("_sub",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_subtract_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_sub",
&NumericDispatch::subtract);
}
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_cmpeq_gco_gco_pm("_cmpeq",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_cmpeq_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_cmpeq",
&NumericDispatch::cmp_equal);
}
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_cmpne_gco_gco_pm("_cmpne",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_cmpne_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_cmpne",
&NumericDispatch::cmp_notequal);
}
DPrimitive_gco_2_gco_gco
NumericPrimitives::s_cmplt_gco_gco_pm("_cmplt",
DPrimitive_gco_2_gco_gco *
NumericPrimitives::make_cmplt_pm(obj<AAllocator> mm)
{
return DPrimitive_gco_2_gco_gco::_make(mm, "_cmplt",
&NumericDispatch::cmp_less);
}
} /*namespace scm*/
} /*namespace xo*/

View file

@ -7,14 +7,20 @@
#include <xo/procedure2/init_procedure2.hpp>
#include "Subsystem.hpp"
#include "numeric_register_facets.hpp"
#include "numeric_register_primitives.hpp"
namespace xo {
using xo::scm::numeric_register_facets;
using xo::scm::numeric_register_primitives;
using xo::scm::PrimitiveRegistry;
void
InitSubsys<S_numeric_tag>::init()
{
numeric_register_facets();
PrimitiveRegistry::instance().register_primitives(&numeric_register_primitives);
}
InitEvidence

View file

@ -0,0 +1,81 @@
/** @file numeric_register_primitives.cpp
*
* @author Roland Conybeare, Mar 2026
**/
#include "numeric_register_primitives.hpp"
#include "NumericPrimitives.hpp"
#include "NumericDispatch.hpp"
#include <xo/procedure2/Primitive_gco_2_gco_gco.hpp>
#include <xo/indentlog/scope.hpp>
namespace xo {
using xo::mm::AAllocator;
using xo::scope;
namespace scm {
namespace {
bool install_aux(InstallSink sink,
DPrimitive_gco_2_gco_gco * pm,
InstallFlags flags)
{
if (flags != InstallFlags::f_none) {
return sink(pm->name(),
pm->fn_td(),
obj<AProcedure,DPrimitive_gco_2_gco_gco>(pm),
flags);
} else {
return true;
}
}
bool install_aux(InstallSink sink,
obj<AAllocator> mm,
std::string_view name,
obj<AGCObject> (*impl)(obj<ARuntimeContext> rcx,
obj<AGCObject> x,
obj<AGCObject> y),
InstallFlags flags)
{
if (flags != InstallFlags::f_none) {
auto pm
= DPrimitive_gco_2_gco_gco::_make(mm, name, impl);
return install_aux(sink, pm, flags);
} else {
return true;
}
}
}
bool
numeric_register_primitives(obj<AAllocator> mm, InstallSink sink, InstallFlags flags)
{
scope log(XO_DEBUG(true));
bool ok = true;
ok = ok & install_aux(sink,
NumericPrimitives::make_multiply_pm(mm),
flags & InstallFlags::f_essential);
ok = ok & install_aux(sink,
NumericPrimitives::make_divide_pm(mm),
flags & InstallFlags::f_essential);
ok = ok & install_aux(sink, mm, "_add", &NumericDispatch::add,
flags & InstallFlags::f_essential);
ok = ok & install_aux(sink, mm, "_sub", &NumericDispatch::subtract,
flags & InstallFlags::f_essential);
ok = ok & install_aux(sink, mm, "_cmpeq", &NumericDispatch::cmp_equal,
flags & InstallFlags::f_essential);
ok = ok & install_aux(sink, mm, "_cmpne", &NumericDispatch::cmp_notequal,
flags & InstallFlags::f_essential);
ok = ok & install_aux(sink, mm, "_cmplt", &NumericDispatch::cmp_less,
flags & InstallFlags::f_essential);
return ok;
}
}
} /*namespace xo*/
/* end numeric_register_primitives.cpp */

View file

@ -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")

View file

@ -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<T>) -> list<T>
* @endpre
* but implementation has signature:
* @pre
* (obj<AGCobject> x obj<AGCObject,DList>) -> obj<AGCObject,DList>
* @endpre
**/
template <typename Fn>
class Primitive {
@ -70,13 +82,28 @@ namespace xo {
using ppindentinfo = xo::print::ppindentinfo;
public:
Primitive(std::string_view name, Fn fn) : name_{name},
/** @defgroup scm-primitive-ctors constructors **/
///@{
Primitive(std::string_view name, Fn fn)
: name_{name},
fn_td_{Reflect::require<Fn>()},
fn_{fn} {}
static Primitive * _make(obj<AAllocator> mm, std::string_view name, Fn fn) {
void * mem = mm.alloc_for<Primitive>();
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<Traits::n_args>{});
}
///@}
/** @defgroup scm-primitive-printable-facet **/
///@{
@ -166,8 +194,12 @@ namespace xo {
template <typename Fn>
std::size_t
Primitive<Fn>::forward_children(obj<ACollector>) noexcept {
// Primitive holds no GC refs (just string_view + function pointer)
Primitive<Fn>::forward_children(obj<ACollector> gc) noexcept {
{
auto e = type_.to_facet<AGCObject>(); // FacetRegistry dep
gc.forward_inplace(e.iface(), (void **)&(type_.data_));
}
return this->shallow_size();
}

View file

@ -0,0 +1,89 @@
/** @file PrimitiveRegistry.hpp
*
* @author Roland Conybeare, Mar 2026
**/
#pragma once
#include "Procedure.hpp"
#include <xo/alloc2/Allocator.hpp>
#include <xo/reflect/TypeDescr.hpp>
#include <functional>
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<uint64_t>(x) & static_cast<uint64_t>(y));
}
/** provided by VSM to receive created primitives.
* InstallSink(pm) adopts a primitive
**/
using InstallSink = std::function<bool (std::string_view name,
xo::reflect::TypeDescr fn_td,
obj<AProcedure> 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<bool (obj<AAllocator> 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<AAllocator> mm,
InstallSink sink,
InstallFlags flags);
private:
/** a set of factories that create primitives **/
std::vector<InstallSource> init_seq_v_;
};
} /*namespace scm*/
} /*namespace xo*/
/* end PrimitiveRegistry.hpp */

View file

@ -0,0 +1,18 @@
/** @file procedure2_register_primitives.hpp
*
* @author Roland Conybeare, Mar 2026
**/
#pragma once
#include "PrimitiveRegistry.hpp"
#include <xo/alloc2/Collector.hpp>
namespace xo {
namespace scm {
/** Register gc-aware (AGCObject,DRepr) combinations with garbage collector @p gc **/
bool procedure2_register_primitives(obj<xo::mm::AAllocator> gc, InstallSink sink);
}
}
/* end procedure2_register_primitives.hpp */

View file

@ -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)

View file

@ -0,0 +1,49 @@
/** @file PrimitiveRegistry.cpp
*
* @author Roland Conybeare, Mar 2026
**/
#include "PrimitiveRegistry.hpp"
#include <xo/indentlog/scope.hpp>
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<AAllocator> 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*/

View file

@ -37,187 +37,6 @@ namespace xo {
}
#endif
#ifdef OBSOLETE // see xo-numeric/xo/numeric/NumericPrimitives.cpp
obj<AGCObject>
mul_gco_gco(obj<ARuntimeContext> rcx,
obj<AGCObject> x_gco,
obj<AGCObject> y_gco)
{
using xo::reflect::typeseq;
obj<AAllocator> 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<DInteger>()) {
// i64 * ..
long x = GCObjectConversion<long>::from_gco(mm, x_gco);
if (y_tseq == typeseq::id<DInteger>()) {
// i64 * i64
long y = GCObjectConversion<long>::from_gco(mm, y_gco);
return DInteger::box<AGCObject>(mm, x * y);
} else if (y_tseq == typeseq::id<DFloat>()) {
// i64 * f64
double y = GCObjectConversion<double>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(mm, x * y);
}
} else if (x_tseq == typeseq::id<DFloat>()) {
if (y_tseq == typeseq::id<DInteger>()) {
// f64 * i64.
double x = GCObjectConversion<double>::from_gco(mm, x_gco);
long y = GCObjectConversion<long>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(mm, x * y);
} else if (y_tseq == typeseq::id<DFloat>()) {
// f64 * f64.
double x = GCObjectConversion<double>::from_gco(mm, x_gco);
double y = GCObjectConversion<double>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(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<AGCObject>();
}
obj<AGCObject>
sub_gco_gco(obj<ARuntimeContext> rcx,
obj<AGCObject> x_gco,
obj<AGCObject> y_gco)
{
using xo::reflect::typeseq;
obj<AAllocator> 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<DInteger>()) {
// i64 * ..
long x = GCObjectConversion<long>::from_gco(mm, x_gco);
if (y_tseq == typeseq::id<DInteger>()) {
// i64 * i64
long y = GCObjectConversion<long>::from_gco(mm, y_gco);
return DInteger::box<AGCObject>(mm, x - y);
} else if (y_tseq == typeseq::id<DFloat>()) {
// i64 * f64
double y = GCObjectConversion<double>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(mm, x - y);
}
} else if (x_tseq == typeseq::id<DFloat>()) {
if (y_tseq == typeseq::id<DInteger>()) {
// f64 * i64.
double x = GCObjectConversion<double>::from_gco(mm, x_gco);
long y = GCObjectConversion<long>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(mm, x - y);
} else if (y_tseq == typeseq::id<DFloat>()) {
// f64 * f64.
double x = GCObjectConversion<double>::from_gco(mm, x_gco);
double y = GCObjectConversion<double>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(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<AGCObject>();
}
obj<AGCObject>
equal_gco_gco(obj<ARuntimeContext> rcx,
obj<AGCObject> x_gco,
obj<AGCObject> y_gco)
{
using xo::reflect::typeseq;
obj<AAllocator> 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<DInteger>()) {
// i64 * ..
long x = GCObjectConversion<long>::from_gco(mm, x_gco);
if (y_tseq == typeseq::id<DInteger>()) {
// i64 == i64
long y = GCObjectConversion<long>::from_gco(mm, y_gco);
return DBoolean::box<AGCObject>(mm, x == y);
} else if (y_tseq == typeseq::id<DFloat>()) {
// i64 == f64
double y = GCObjectConversion<double>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(mm, static_cast<double>(x) == y);
}
} else if (x_tseq == typeseq::id<DFloat>()) {
if (y_tseq == typeseq::id<DInteger>()) {
// f64 == i64.
double x = GCObjectConversion<double>::from_gco(mm, x_gco);
long y = GCObjectConversion<long>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(mm, x == static_cast<double>(y));
} else if (y_tseq == typeseq::id<DFloat>()) {
// f64 * f64.
double x = GCObjectConversion<double>::from_gco(mm, x_gco);
double y = GCObjectConversion<double>::from_gco(mm, y_gco);
return DFloat::box<AGCObject>(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<AGCObject>();
}
#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",

View file

@ -337,6 +337,22 @@ xo_add_genfacetimpl(
# ----------------------------------------------------------------
# note: manual target; generated code committed to git
xo_add_genfacetimpl(
TARGET xo-reader2-facetimpl-gcobject-globalenv
FACET_PKG xo_alloc2
INPUT idl/IGCObject_DGlobalEnv.json5
)
# note: manual target; generated code committed to git
xo_add_genfacetimpl(
TARGET xo-reader2-facetimpl-printable-globalenv
FACET_PKG xo_printable2
INPUT idl/IPrintable_DGlobalEnv.json5
)
# ----------------------------------------------------------------
xo_add_genfacet_all(xo-reader2-genfacet-all)
# ----------------------------------------------------------------

View file

@ -1,6 +1,6 @@
{
mode: "implementation",
output_cpp_dir: "src/interpreter2",
output_cpp_dir: "src/reader2/facet",
output_hpp_dir: "include/xo/interpreter2",
output_impl_subdir: "env",
includes: [

View file

@ -1,6 +1,6 @@
{
mode: "implementation",
output_cpp_dir: "src/interpreter2",
output_cpp_dir: "src/interpreter2/facet",
output_hpp_dir: "include/xo/interpreter2",
output_impl_subdir: "env",
includes: [ "<xo/printable2/Printable.hpp>",

View file

@ -5,6 +5,7 @@
#pragma once
#include <xo/procedure2/PrimitiveRegistry.hpp>
#include <xo/arena/ArenaHashMapConfig.hpp>
#include <xo/arena/ArenaConfig.hpp>
@ -55,6 +56,9 @@ namespace xo {
/** max capacity for unique string table **/
size_t max_stringtable_capacity_ = 4096;
/** flags controlling which primitives to install **/
InstallFlags pm_install_flags_ = InstallFlags::f_all;
/** control SchematikaParser debug logging **/
bool debug_flag_ = false;
};

View file

@ -6,11 +6,13 @@
#pragma once
#include "ParserResult.hpp"
#include "GlobalEnv.hpp"
#include <xo/expression2/DGlobalSymtab.hpp>
#include <xo/expression2/DLocalSymtab.hpp>
#include <xo/expression2/DVariable.hpp>
#include <xo/expression2/VarRef.hpp>
#include <xo/tokenizer2/Token.hpp>
#include <xo/procedure2/PrimitiveRegistry.hpp>
#include <xo/type/Type.hpp>
#include <xo/object2/DArray.hpp>
#include <xo/stringtable2/StringTable.hpp>
@ -45,6 +47,9 @@ namespace xo {
using size_type = std::size_t;
public:
/** @defgroup scm-parserstatemachine-ctors constructors **/
///@{
/**
* @p config arena configuration for parser state
* @p symtab_var_config configuration for global symtab variables
@ -53,6 +58,8 @@ namespace xo {
* (maps to separate dedicated memory)
* @p max_stringtable_capacity
* hard max size for unique stringtable
* @p pm_install_flags
* flags controlling primitives to install
* @p expr_alloc allocator for schematika expressions.
* Probably shared with execution.
* @p aux_alloc auxiliary allocator for non-copyable memory
@ -64,12 +71,17 @@ namespace xo {
const ArenaHashMapConfig & symtab_var_config,
const ArenaHashMapConfig & symtab_type_config,
size_type max_stringtable_capacity,
InstallFlags pm_install_flags,
obj<AAllocator> expr_alloc,
obj<AAllocator> aux_alloc);
/** non-trivial dtor for @ref global_symtab_ **/
~ParserStateMachine() = default;
/** not copyable (need to put global_env into gc **/
ParserStateMachine(const ParserStateMachine & other) = delete;
/** non-trivial dtor for @ref global_symtab_ **/
~ParserStateMachine();
///@}
/** @defgroup scm-parserstatemachine-accessors accessor methods **/
///@{
@ -80,6 +92,21 @@ namespace xo {
DLocalSymtab * local_symtab() const noexcept { return local_symtab_; }
const ParserResult & result() const noexcept { return result_; }
/** polymoprhihc multiply primitive. Use to implement infix op* **/
obj<AGCObject> multiply_pm() const;
/** polymorphic divide primitive. Use to implement infix op/ **/
obj<AGCObject> divide_pm() const;
/** polymorphic add primitive. Use to implement infix op+ **/
obj<AGCObject> add_pm() const;
/** polymorphic subtract primitive. Use to implement infix op- **/
obj<AGCObject> subtract_pm() const;
/** polymorphic equality comparison. Use to implement infix op== **/
obj<AGCObject> cmpeq_pm() const;
/** polymorphic inequality comparison. Use to implement infix op!= **/
obj<AGCObject> cmpne_pm() const;
/** polymorphich less-than comparison. Use to implement infix op< **/
obj<AGCObject> cmplt_pm() const;
/** true iff state machine is currently idle (at top-level) **/
bool is_at_toplevel() const noexcept;
@ -378,6 +405,20 @@ namespace xo {
**/
DLocalSymtab * local_symtab_ = nullptr;
/** global variable bindings (builtin primitives) **/
obj<AGCObject,DGlobalEnv> global_env_;
/** bindings for special builtin primitives
* (asociated with hardwired operator syntax)
**/
Binding multiply_binding_;
Binding divide_binding_;
Binding add_binding_;
Binding subtract_binding_;
Binding cmpeq_binding_;
Binding cmpne_binding_;
Binding cmplt_binding_;
/** current output from parser **/
ParserResult result_;

View file

@ -5,6 +5,7 @@
#pragma once
#include <xo/procedure2/PrimitiveRegistry.hpp>
#include <xo/arena/CircularBufferConfig.hpp>
#include <xo/arena/ArenaHashMapConfig.hpp>
#include <xo/arena/ArenaConfig.hpp>
@ -71,6 +72,9 @@ namespace xo {
/** max size (in bytes) of stringtable **/
size_t max_stringtable_cap_ = 64*1024;
/** flags controlling which primitives to install **/
InstallFlags pm_install_flags_ = InstallFlags::f_all;
/** debug flag for schematika_reader **/
bool reader_debug_flag_ = false;
};

View file

@ -14,6 +14,10 @@ set(SELF_SRCS
ParserStack.cpp
ParserResult.cpp
DGlobalEnv.cpp
facet/IGCObject_DGlobalEnv.cpp
facet/IPrintable_DGlobalEnv.cpp
syntaxstatetype.cpp
ISyntaxStateMachine_Any.cpp

View file

@ -603,173 +603,6 @@ namespace xo {
p_psm->on_error(self_name, std::move(errmsg));
}
rp<Expression>
progress_xs::assemble_expr(parserstatemachine * p_psm) {
/* need to defer building Apply incase expr followed by higher-precedence operator:
* consider input like
* 3.14 + 2.0 * ...
*/
constexpr const char * c_self_name = "progress_xs::assemble_expr";
if ((op_type_ != optype::invalid) && (rhs_.get() == nullptr)) {
std::string errmsg = tostr("expected expression on rhs of operator op",
xtag("lhs", lhs_),
xtag("op", op_type_));
p_psm->on_error(c_self_name, errmsg);
}
/* consecutive expressions not legal, e.g:
* 3.14 6.28
* but expressions surrounding an infix operators is:
* 3.14 / 6.28
*/
switch (op_type_) {
case optype::invalid:
return this->lhs_;
case optype::op_assign:
{
bp<Variable> lhs = Variable::from(this->lhs_);
if (!lhs) {
throw std::runtime_error
(tostr("progress_xs::assemble_expr",
" expect variable on lhs of assignment operator :=",
xtag("lhs", lhs_),
xtag("rhs", rhs_)));
}
return AssignExpr::make(lhs.promote(),
this->rhs_);
}
case optype::op_equal:
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_cmp_eq_i64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_not_equal:
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_cmp_ne_i64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_less:
// TODO: floating-point less-than
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_cmp_lt_i64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_less_equal:
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_cmp_le_i64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_great:
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_cmp_gt_i64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_great_equal:
// TODO: upconvert integer->double
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_cmp_ge_i64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
assert(false);
case optype::op_add:
// TODO: upconvert integer->double
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_add2_i64(lhs_, rhs_);
} else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) {
return Apply::make_add2_f64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_subtract:
// TODO: upconvert integer->double
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_sub2_i64(lhs_, rhs_);
} else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) {
return Apply::make_sub2_f64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_multiply:
// TODO: upconvert integer->double
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_mul2_i64(lhs_, rhs_);
} else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) {
return Apply::make_mul2_f64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::op_divide:
// TODO: upconvert integer->double
if (lhs_->valuetype()->is_i64() && rhs_->valuetype()->is_i64()) {
return Apply::make_div2_i64(lhs_, rhs_);
} else if (lhs_->valuetype()->is_f64() && rhs_->valuetype()->is_f64()) {
return Apply::make_div2_f64(lhs_, rhs_);
} else {
this->apply_type_error(c_self_name,
op_type_, lhs_, rhs_, p_psm);
return nullptr;
}
break;
case optype::n_optype:
/* unreachable */
assert(false);
return nullptr;
}
return nullptr;
}
void
progress_xs::on_expr(bp<Expression> expr,
parserstatemachine * p_psm)
@ -1216,11 +1049,10 @@ namespace xo {
obj<AExpression>
assemble_numeric_expr_aux(obj<AAllocator> expr_alloc,
const TypeRef::prefix_type & prefix,
DPrimitive_gco_2_gco_gco * p_gco_pm,
obj<AGCObject> pm_obj,
obj<AExpression> lhs,
obj<AExpression> rhs)
{
auto pm_obj = with_facet<AGCObject>::mkobj(p_gco_pm);
auto fn_expr = DConstant::make(expr_alloc, pm_obj);
/* note:
@ -1247,6 +1079,23 @@ namespace xo {
tref, fn_expr, lhs, rhs);
}
#ifdef OBSOLETE
obj<AExpression>
assemble_numeric_expr_aux(obj<AAllocator> expr_alloc,
const TypeRef::prefix_type & prefix,
DPrimitive_gco_2_gco_gco * p_gco_pm,
obj<AExpression> lhs,
obj<AExpression> rhs)
{
auto pm_obj = with_facet<AGCObject>::mkobj(p_gco_pm);
return assemble_numeric_expr_aux(expr_alloc,
prefix,
pm_obj,
lhs, rhs);
}
#endif
}
obj<AExpression>
@ -1288,41 +1137,21 @@ namespace xo {
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_cmpeq_gco"),
&NumericPrimitives::s_cmpeq_gco_gco_pm,
p_psm->cmpeq_pm(),
lhs_, rhs_);
#ifdef OBSOLETE
{
auto pm_obj = (with_facet<AGCObject>::mkobj
(&NumericPrimitives::s_cmpeq_gco_gco_pm));
auto fn_expr = (DConstant::make
(p_psm->expr_alloc(), pm_obj));
// see note on op_multiply
TypeRef tref = TypeRef::dwim
(TypeRef::prefix_type::from_chars("_equal_gco"),
nullptr);
return DApplyExpr::make2(p_psm->expr_alloc(),
tref,
fn_expr, lhs_, rhs_);
}
break;
#endif
case optype::op_not_equal:
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_cmpne_gco"),
&NumericPrimitives::s_cmpne_gco_gco_pm,
p_psm->cmpne_pm(),
lhs_, rhs_);
case optype::op_less:
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_cmplt_gco"),
&NumericPrimitives::s_cmplt_gco_gco_pm,
p_psm->cmplt_pm(),
lhs_, rhs_);
case optype::op_less_equal:
@ -1335,45 +1164,18 @@ namespace xo {
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_mul_gco"),
&NumericPrimitives::s_mul_gco_gco_pm,
p_psm->multiply_pm(), //&NumericPrimitives::s_mul_gco_gco_pm
lhs_, rhs_);
#ifdef OBSOLETE
{
auto pm_obj = (with_facet<AGCObject>::mkobj
(&NumericPrimitives::s_mul_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("_mul_gco"),
nullptr);
return DApplyExpr::make2(p_psm->expr_alloc(),
tref, fn_expr, lhs_, rhs_);
}
#endif
break;
case optype::op_divide:
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_div_gco"),
p_psm->divide_pm(), // &NumericPrimitives::s_div_gco_gco_pm
lhs_, rhs_);
#ifdef OBSOLETE
{
auto pm_obj = (with_facet<AGCObject>::mkobj
(&NumericPrimitives::s_div_gco_gco_pm));
@ -1405,10 +1207,17 @@ namespace xo {
return DApplyExpr::make2(p_psm->expr_alloc(),
tref, fn_expr, lhs_, rhs_);
}
#endif
break;
case optype::op_add:
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_add_gco"),
p_psm->add_pm(),
lhs_, rhs_);
#ifdef OBSOLETE
{
auto pm_obj = (with_facet<AGCObject>::mkobj
(&NumericPrimitives::s_add_gco_gco_pm));
@ -1440,10 +1249,18 @@ namespace xo {
return DApplyExpr::make2(p_psm->expr_alloc(),
tref, fn_expr, lhs_, rhs_);
}
#endif
break;
case optype::op_subtract: /* editor bait: op_minus */
return assemble_numeric_expr_aux
(p_psm->expr_alloc(),
TypeRef::prefix_type::from_chars("_sub_gco"),
p_psm->subtract_pm(),
lhs_, rhs_);
#ifdef OBSOLETE
{
auto pm_obj = (with_facet<AGCObject>::mkobj
(&NumericPrimitives::s_sub_gco_gco_pm));
@ -1459,6 +1276,7 @@ namespace xo {
return DApplyExpr::make2(p_psm->expr_alloc(),
tref, fn_expr, lhs_, rhs_);
}
#endif
break;

View file

@ -8,8 +8,10 @@
#include "SyntaxStateMachine.hpp"
#include "ToplevelSeqSsm.hpp"
#include "DefineSsm.hpp"
#include <xo/procedure2/PrimitiveRegistry.hpp>
#include <xo/object2/array/IPrintable_DArray.hpp>
#include <xo/printable2/Printable.hpp>
#include <xo/alloc2/Collector.hpp>
#include <xo/alloc2/arena/IAllocator_DArena.hpp>
#include <xo/facet/FacetRegistry.hpp>
#include <xo/indentlog/scope.hpp>

View file

@ -28,6 +28,7 @@ namespace xo {
cfg.symtab_var_config_,
cfg.symtab_types_config_,
cfg.max_stringtable_capacity_,
cfg.pm_install_flags_,
expr_alloc,
aux_alloc
},

View file

@ -18,6 +18,7 @@ namespace xo {
config.symtab_var_config_,
config.symtab_types_config_,
config.max_stringtable_cap_,
config.pm_install_flags_,
config.parser_debug_flag_),
expr_alloc,
aux_alloc},

View file

@ -33,6 +33,7 @@
namespace xo {
using xo::print::APrintable;
using xo::mm::AGCObject;
using xo::facet::FacetRegistry;
using xo::facet::TypeRegistry;
using xo::facet::typeseq;
@ -43,6 +44,13 @@ namespace xo {
{
scope log(XO_DEBUG(true));
// GlobalEnv
FacetRegistry::register_impl<AGCObject, DGlobalEnv>();
FacetRegistry::register_impl<APrintable, DGlobalEnv>();
// SyntaxStateMachine
FacetRegistry::register_impl<ASyntaxStateMachine, DToplevelSeqSsm>();
FacetRegistry::register_impl<APrintable, DToplevelSeqSsm>();
@ -105,6 +113,7 @@ namespace xo {
// misc types showing up in parser stack arena
TypeRegistry::register_type<ParserStack>();
log && log(xtag("DGlobalEnv.tseq", typeseq::id<DGlobalEnv>()));
log && log(xtag("DToplevelSeqSsm.tseq", typeseq::id<DToplevelSeqSsm>()));
log && log(xtag("DDefineSsm.tseq", typeseq::id<DDefineSsm>()));
log && log(xtag("DDeftypeSsm.tseq", typeseq::id<DDeftypeSsm>()));

View file

@ -4,22 +4,25 @@
**/
#include "reader2_register_types.hpp"
#include "GlobalEnv.hpp"
#include <xo/indentlog/scope.hpp>
namespace xo {
using xo::mm::ACollector;
using xo::mm::AGCObject;
using xo::facet::impl_for;
using xo::scope;
namespace scm {
bool
reader2_register_types(obj<ACollector> /*gc*/)
reader2_register_types(obj<ACollector> gc)
{
scope log(XO_DEBUG(true));
bool ok = true;
/* no gc-aware types yet; scaffold for future use */
ok &= gc.install_type(impl_for<AGCObject, DGlobalEnv>());
return ok;
}