diff --git a/include/xo/interpreter2/DClosure.hpp b/include/xo/interpreter2/DClosure.hpp new file mode 100644 index 00000000..09966038 --- /dev/null +++ b/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/include/xo/interpreter2/DLocalEnv.hpp b/include/xo/interpreter2/DLocalEnv.hpp new file mode 100644 index 00000000..fec8148d --- /dev/null +++ b/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/include/xo/interpreter2/DVsmApplyFrame.hpp b/include/xo/interpreter2/DVsmApplyFrame.hpp index c898c602..72900eb2 100644 --- a/include/xo/interpreter2/DVsmApplyFrame.hpp +++ b/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/include/xo/interpreter2/LocalEnv.hpp b/include/xo/interpreter2/LocalEnv.hpp new file mode 100644 index 00000000..8976452f --- /dev/null +++ b/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/src/interpreter2/CMakeLists.txt b/src/interpreter2/CMakeLists.txt index 635ecff3..e0903be8 100644 --- a/src/interpreter2/CMakeLists.txt +++ b/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/src/interpreter2/DClosure.cpp b/src/interpreter2/DClosure.cpp new file mode 100644 index 00000000..6d9bc446 --- /dev/null +++ b/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/src/interpreter2/DLocalEnv.cpp b/src/interpreter2/DLocalEnv.cpp new file mode 100644 index 00000000..3aba3aa8 --- /dev/null +++ b/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 */