xo-interpreter2 stack: refactor + bugfix operator expr
This commit is contained in:
parent
c8bc13cb2e
commit
6c7216ed7d
7 changed files with 195 additions and 200 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
89
include/xo/procedure2/PrimitiveRegistry.hpp
Normal file
89
include/xo/procedure2/PrimitiveRegistry.hpp
Normal 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 */
|
||||
18
include/xo/procedure2/procedure2_register_primitives.hpp
Normal file
18
include/xo/procedure2/procedure2_register_primitives.hpp
Normal 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 */
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
49
src/procedure2/PrimitiveRegistry.cpp
Normal file
49
src/procedure2/PrimitiveRegistry.cpp
Normal 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*/
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue