/** @file DPrimitive.hpp * * @author Roland Conybeare, Jan 2025 **/ #pragma once #include "RuntimeContext.hpp" #include #include #include #include #include #include #include #include #include #include #include #include namespace xo { namespace scm { namespace detail { /** @brief Extract return type and argument types from a function type. * * Primary template (undefined) - specializations handle specific cases **/ template struct PmFnTraits; /** specialization for function pointers **/ template struct PmFnTraits rcx, Args...)> { /** function return type **/ using return_type = R; /** tuple type for function arguments (except for runtime context) **/ using args_tuple = std::tuple; /** number of arguments (except for runtime context) **/ static constexpr std::size_t n_args = sizeof...(Args); /** arg_type is the type of the i'th argument to Fn. * (starting from argument after runtime context) **/ template using arg_type = std::tuple_element_t; }; /** specialization for function references **/ template struct PmFnTraits, Args...)> : PmFnTraits, Args...)> {}; /** specialization for plain function types **/ template struct PmFnTraits, Args...)> : PmFnTraits, Args...)> {}; } /** @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) -> list * @endpre * but implementation has signature: * @pre * (obj x obj) -> obj * @endpre **/ template class Primitive { public: using FunctionPtrType = Fn; using Traits = detail::PmFnTraits; //using ACollector = xo::mm::ACollector; using AGCObject = xo::mm::AGCObject; using AGCObjectVisitor = xo::mm::AGCObjectVisitor; using AAllocator = xo::mm::AAllocator; using DArray = xo::scm::DArray; using Reflect = xo::reflect::Reflect; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; public: /** @defgroup scm-primitive-ctors constructors **/ ///@{ Primitive(std::string_view name, obj type, Fn fn) : name_{name}, type_{type}, fn_td_{Reflect::require()}, fn_{fn} {} static Primitive * _make(obj mm, std::string_view name, Fn fn) { void * mem = mm.alloc_for(); return new (mem) Primitive(name, obj(), fn); } static Primitive * _make(obj mm, std::string_view name, obj type, Fn fn) { void * mem = mm.alloc_for(); return new (mem) Primitive(name, type, fn); } ///@} /** @defgroup scm-primitive-methods general methods **/ ///@{ static constexpr std::int32_t n_args() noexcept { return Traits::n_args; } TypeDescr fn_td() const noexcept { return fn_td_; } std::string_view name() const noexcept { return name_; } bool is_nary() const noexcept { return false; } obj apply_nocheck(obj rcx, const DArray * args) { return _apply_nocheck(rcx, args, std::make_index_sequence{}); } ///@} /** @defgroup scm-primitive-printable-facet **/ ///@{ bool pretty(const ppindentinfo & ppii) const; ///@} /** @defgroup scm-primitive-gcobject-facet **/ ///@{ Primitive * gco_shallow_move(obj gc) noexcept; void visit_gco_children(obj gc) noexcept; ///@} private: template obj _apply_nocheck(obj rcx, const DArray * args, std::index_sequence) { using xo::facet::FacetRegistry; using R = typename Traits::return_type; assert(args); obj mm = rcx.allocator(); R result = fn_(rcx, GCObjectConversion>::from_gco(mm, args->at(Is))... ); return GCObjectConversion::to_gco(mm, result); } private: /** name of this primitive **/ std::string_view name_; /** primitive type-constructor. These are non-trivial to establish; * not convenient to establish in ctor **/ obj type_; /** type description for implementation function * Note that this type description will have additional first argument * for obj **/ TypeDescr fn_td_; /** function implementation **/ Fn fn_; }; /*Primitive*/ template bool Primitive::pretty(const ppindentinfo & ppii) const { return ppii.pps()->pretty_struct (ppii, "Primitive", refrtag("name", name_), refrtag("td", fn_td_), refrtag("fn", fn_)); } template Primitive * Primitive::gco_shallow_move(obj gc) noexcept { return gc.std_move_for(this); } template void Primitive::visit_gco_children(obj gc) noexcept { gc.visit_poly_child(&type_); //{ // auto e = type_.to_facet(); // FacetRegistry dep // gc.forward_inplace(e.iface(), (void **)&(type_.data_)); //} } } /*namespace scm*/ } /*namespace xo*/ /* end DPrimitive.hpp */