diff --git a/xo-alloc2/include/xo/alloc2/alloc/RAllocator.hpp b/xo-alloc2/include/xo/alloc2/alloc/RAllocator.hpp index ad528ba5..ecd80bb7 100644 --- a/xo-alloc2/include/xo/alloc2/alloc/RAllocator.hpp +++ b/xo-alloc2/include/xo/alloc2/alloc/RAllocator.hpp @@ -31,6 +31,11 @@ namespace xo { requires std::is_same_v : Object(iface, data) {} + template + void * alloc_for() noexcept { + return O::iface()->alloc(O::data(), typeseq::id(), sizeof(T)); + } + 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()); } diff --git a/xo-expression2/include/xo/expression2/DLambdaExpr.hpp b/xo-expression2/include/xo/expression2/DLambdaExpr.hpp index 14be115f..2a0cc2c3 100644 --- a/xo-expression2/include/xo/expression2/DLambdaExpr.hpp +++ b/xo-expression2/include/xo/expression2/DLambdaExpr.hpp @@ -23,6 +23,7 @@ namespace xo { using AAllocator = xo::mm::AAllocator; using TypeDescr = xo::reflect::TypeDescr; using ppindentinfo = xo::print::ppindentinfo; + using size_type = DLocalSymtab::size_type; public: @@ -60,6 +61,7 @@ namespace xo { ///@{ DLocalSymtab * local_symtab() const noexcept { return local_symtab_; } + size_type n_args() const noexcept { return local_symtab_->size(); } // get_free_variables() // visit_preorder() diff --git a/xo-expression2/include/xo/expression2/DLocalSymtab.hpp b/xo-expression2/include/xo/expression2/DLocalSymtab.hpp index 01d9aa85..163d031e 100644 --- a/xo-expression2/include/xo/expression2/DLocalSymtab.hpp +++ b/xo-expression2/include/xo/expression2/DLocalSymtab.hpp @@ -101,7 +101,7 @@ namespace xo { private: /** parent symbol table from scoping surrounding this one **/ DLocalSymtab * parent_ = nullptr; - /** actual range of slots_[] array. Can use inices in [0,..,n) **/ + /** actual range of slots_[] array. Can use indices in [0,..,n) **/ size_type capacity_ = 0; /** number of slots in use **/ size_type size_ = 0; diff --git a/xo-expression2/include/xo/expression2/LambdaExpr.hpp b/xo-expression2/include/xo/expression2/LambdaExpr.hpp new file mode 100644 index 00000000..45f86b25 --- /dev/null +++ b/xo-expression2/include/xo/expression2/LambdaExpr.hpp @@ -0,0 +1,13 @@ +/** @file LambdaExpr.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DLambdaExpr.hpp" +#include "detail/IExpression_DLambdaExpr.hpp" +//#include "detail/IGCObject_DLambdaExpr.hpp" +#include "detail/IPrintable_DLambdaExpr.hpp" + +/* end LambdaExpr.hpp */ diff --git a/xo-expression2/include/xo/expression2/LocalSymtab.hpp b/xo-expression2/include/xo/expression2/LocalSymtab.hpp new file mode 100644 index 00000000..4c852652 --- /dev/null +++ b/xo-expression2/include/xo/expression2/LocalSymtab.hpp @@ -0,0 +1,12 @@ +/** @file LocalSymtab.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DLocalSymtab.hpp" +#include "symtab/ISymbolTable_DLocalSymtab.hpp" +#include "symtab/IPrintable_DLocalSymtab.hpp" + +/* end LocalSymtab.hpp */ diff --git a/xo-facet/codegen/genfacet b/xo-facet/codegen/genfacet index c20689d3..8edadc1c 100755 --- a/xo-facet/codegen/genfacet +++ b/xo-facet/codegen/genfacet @@ -314,6 +314,8 @@ def gen_facet_impl(env, router_facet = f'R{facet_name}' # RFoo.hpp router_facet_hpp_fname = f'{router_facet}.hpp' + # user defined content -- whatever you want + router_facet_explicit_content = facet_idl['router_facet_explicit_content'] # ================================================================ # vars for IFacet_DRepr @@ -384,6 +386,7 @@ def gen_facet_impl(env, 'router_facet': router_facet, 'router_facet_hpp_j2': 'router_facet.hpp.j2', 'router_facet_hpp_fname': router_facet_hpp_fname, + 'router_facet_explicit_content': router_facet_explicit_content, # 'types': facet_types, 'local_types': local_types, diff --git a/xo-facet/codegen/router_facet.hpp.j2 b/xo-facet/codegen/router_facet.hpp.j2 index 5c3f6497..ca8d6404 100644 --- a/xo-facet/codegen/router_facet.hpp.j2 +++ b/xo-facet/codegen/router_facet.hpp.j2 @@ -56,6 +56,11 @@ public: ///@{ {% endif %} + // explicit injected content + {% for c in router_facet_explicit_content %} + {{c}} + {% endif %} + // builtin methods typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } void _drop() const noexcept { O::iface()->_drop(O::data()); } diff --git a/xo-interpreter2/include/xo/interpreter2/DClosure.hpp b/xo-interpreter2/include/xo/interpreter2/DClosure.hpp new file mode 100644 index 00000000..09966038 --- /dev/null +++ b/xo-interpreter2/include/xo/interpreter2/DClosure.hpp @@ -0,0 +1,49 @@ +/** @file DClosure.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "LocalEnv.hpp" +#include + +namespace xo { + namespace scm { + + /** @brief runtime representation for a procedure + * + * Maintains lambda + captured lexical context + **/ + class DClosure { + public: + using AAllocator = xo::mm::AAllocator; + using size_type = std::int32_t; + + public: + DClosure(const DLambdaExpr * lm, + const DLocalEnv * env); + + /** create instance using memory from @p mm + * for lambda @p lm with captured environment @p env. + **/ + static DClosure * make(obj mm, + const DLambdaExpr * lm, + const DLocalEnv * env); + + /** for now, support just fixed-arity procedures **/ + bool is_nary() const noexcept { return false; } + /** number of arguments expected by this procedure (-1 if nary) **/ + size_type n_args() const noexcept { return lambda_->n_args(); } + + private: + /** lambda expression **/ + const DLambdaExpr * lambda_ = nullptr; + /** bindings for captured variables + * (from lexical context where lambda evaluated) + **/ + const DLocalEnv * env_ = nullptr; + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DClosure.hpp */ diff --git a/xo-interpreter2/include/xo/interpreter2/DLocalEnv.hpp b/xo-interpreter2/include/xo/interpreter2/DLocalEnv.hpp new file mode 100644 index 00000000..fec8148d --- /dev/null +++ b/xo-interpreter2/include/xo/interpreter2/DLocalEnv.hpp @@ -0,0 +1,67 @@ +/** @file DLocalEnv.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace scm { + + /** @brief bindings for arguments to a lambda + **/ + class DLocalEnv { + public: + using DArray = xo::scm::DArray; + using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using ppindentinfo = xo::print::ppindentinfo; + using size_type = std::uint32_t; + + public: + /** @defgroup scm-localenv-constructors constructors **/ + ///@{ + + /** empty instance with parent @p p for variables in @p symtab **/ + DLocalEnv(DLocalEnv * parent, + DLocalSymtab * symtab, + DArray * args); + + static DLocalEnv * _make_empty(obj mm, + DLocalEnv * parent, + DLocalSymtab * symtab, + DArray * args); + + ///@} + /** @defgroup scm-local-env-methods methods **/ + ///@{ + + DLocalEnv * parent() const noexcept { return parent_; } + size_type size() const noexcept { return symtab_->size(); } + + /** lookup current value associated with binding @p ix **/ + obj lookup_value(Binding ix) const noexcept; + + /** assign value associated with binding @p ix to @p x **/ + void assign_value(Binding ix, obj x); + + ///@} + + private: + /** parent environment (from closure) **/ + DLocalEnv * parent_ = nullptr; + /** bind values for variables in this symbol table **/ + DLocalSymtab * symtab_ = nullptr; + /** bindings. + * (*args)[i] associates a value with symtab->slots_[i] + **/ + DArray * args_ = nullptr;; + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DLocalEnv.hpp */ diff --git a/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp b/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp index c898c602..72900eb2 100644 --- a/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp +++ b/xo-interpreter2/include/xo/interpreter2/DVsmApplyFrame.hpp @@ -21,6 +21,7 @@ namespace xo { VsmInstr old_cont, DArray * args); + /** create instance using memory from @p mm **/ static DVsmApplyFrame * make(obj mm, obj old_parent, VsmInstr old_cont, diff --git a/xo-interpreter2/include/xo/interpreter2/LocalEnv.hpp b/xo-interpreter2/include/xo/interpreter2/LocalEnv.hpp new file mode 100644 index 00000000..8976452f --- /dev/null +++ b/xo-interpreter2/include/xo/interpreter2/LocalEnv.hpp @@ -0,0 +1,12 @@ +/** @file LocalEnv.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "DLocalEnv.hpp" +//#include "detail/IGCObject_DLocalEnv.hpp" +//#include "detail/IPrintable_DLocalEnv.hpp" + +/* end LocalEnv.hpp */ diff --git a/xo-interpreter2/src/interpreter2/CMakeLists.txt b/xo-interpreter2/src/interpreter2/CMakeLists.txt index 635ecff3..e0903be8 100644 --- a/xo-interpreter2/src/interpreter2/CMakeLists.txt +++ b/xo-interpreter2/src/interpreter2/CMakeLists.txt @@ -17,6 +17,10 @@ set(SELF_SRCS IPrintable_DVsmApplyFrame.cpp VsmInstr.cpp + + DClosure.cpp + DLocalEnv.cpp + #IExpression_Any.cpp ) diff --git a/xo-interpreter2/src/interpreter2/DClosure.cpp b/xo-interpreter2/src/interpreter2/DClosure.cpp new file mode 100644 index 00000000..6d9bc446 --- /dev/null +++ b/xo-interpreter2/src/interpreter2/DClosure.cpp @@ -0,0 +1,29 @@ +/** @file DClosure.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "DClosure.hpp" + +namespace xo { + namespace scm { + + DClosure::DClosure(const DLambdaExpr * lm, + const DLocalEnv * env) + : lambda_{lm}, env_{env} + {} + + DClosure * + DClosure::make(obj mm, + const DLambdaExpr * lm, + const DLocalEnv * env) + { + void * mem = mm.alloc_for(); + + return new (mem) DClosure(lm, env); + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DClosure.cpp */ diff --git a/xo-interpreter2/src/interpreter2/DLocalEnv.cpp b/xo-interpreter2/src/interpreter2/DLocalEnv.cpp new file mode 100644 index 00000000..3aba3aa8 --- /dev/null +++ b/xo-interpreter2/src/interpreter2/DLocalEnv.cpp @@ -0,0 +1,92 @@ +/** @file DLocalEnv.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "DLocalEnv.hpp" +#include + +namespace xo { + using xo::mm::AGCObject; + using xo::reflect::typeseq; + + namespace scm { + + DLocalEnv::DLocalEnv(DLocalEnv * parent, + DLocalSymtab * symtab, + DArray * args) + : parent_{parent}, + symtab_{symtab}, + args_{args} + {} + + DLocalEnv * + DLocalEnv::_make_empty(obj mm, + DLocalEnv * parent, + DLocalSymtab * symtab, + DArray * args) + { + assert(symtab); + + void * mem = mm.alloc_for(); + + return new (mem) DLocalEnv(parent, symtab, args); + } + + obj + DLocalEnv::lookup_value(Binding ix) const noexcept + { + assert(!ix.is_global()); + + const DLocalEnv * env = this; + + for (auto i = ix.i_link(); i > 0; --i) { + env = env->parent(); + } + + if (env) { + auto j = ix.j_slot(); + + if (j < static_cast(env->size())) { + return (*(env->args_))[j]; + } else { + assert(false); + } + } else { + assert(false); + } + + /* something terribly wrong if control here */ + return obj(); + } + + void + DLocalEnv::assign_value(Binding ix, obj x) + { + assert(!ix.is_global()); + + const DLocalEnv * env = this; + + for (auto i = ix.i_link(); i > 0; --i) { + env = env->parent(); + } + + if (env) { + auto j = ix.j_slot(); + + if (j < static_cast(env->size())) { + (*(env->args_))[j] = x; + } else { + assert(false); + } + } else { + assert(false); + } + + /* something terribly wrong if control here */ + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DLocalEnv.cpp */