/** @file DLocalSymtab.hpp * * @author Roland Conybeare, Jan 2026 **/ #pragma once #include "Binding.hpp" #include "DVariable.hpp" #include "DUniqueString.hpp" #include namespace xo { namespace scm { /** @class DLocalSymtab * @brief symbol table for a local stack frame **/ struct DLocalSymtab { public: using DArray = xo::scm::DArray; using ppindentinfo = xo::print::ppindentinfo; using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using AGCObject = xo::mm::AGCObject; /* note: uint16_t would be fine too */ using size_type = std::uint32_t; struct Slot { Slot() = default; explicit Slot(DVariable * var) : var_{var} {} /** variable representing a formal argument. * binding will be correct only within the same layer * as top-level lambda body * (i.e. up to the doorstep of each and every nested lambda) **/ DVariable * var_ = nullptr; }; public: /** @defgroup scm-lambdaexpr-constructors **/ ///@{ /** empty instance with parent @p p, using arrays @p vars for variables * and @p types for type definitions. **/ DLocalSymtab(DLocalSymtab * p, DArray * nv, DArray * nt); /** scaffold empty symtab instance, * capacity for @p nv vars and @p nt types, * using memory from allocator @p mm. * Symtab chains to parent @p p. **/ static DLocalSymtab * _make_empty(obj mm, DLocalSymtab * p, size_type nv, size_type nt); ///@} /** @defgroup scm-lambdaexpr-methods **/ ///@{ DLocalSymtab * parent() const noexcept { return parent_; } //size_type capacity() const noexcept { return capacity_; } size_type n_vars() const noexcept { return vars_->size(); } size_type n_types() const noexcept { return types_->size(); } DVariable * lookup_var(Binding ix) noexcept; /** increase slot size (provided below capacity) to append * binding for one local variable. Local variable will be allocated * from @p mm, named @p name, with type described by @p typeref. **/ Binding append_var(obj mm, const DUniqueString * name, TypeRef typeref); /** increase slot size (provided below capacity) to append * binding for one local type. Local type will be allocated * from @p mm, named @p name, with type described by @p type. **/ void append_type(obj mm, const DUniqueString * name, obj type); ///@} /** @defgroup xo-localsymtab-symboltable-facet symboltable facet**/ ///@{ /** true for global symbol table **/ bool is_global_symtab() const noexcept { return false; } /** lookup binding for variable @p sym **/ Binding lookup_binding(const DUniqueString * sym) const noexcept; ///@} /** @defgroup xo-localsymtab-gcobject-facet gcobject facet **/ ///@{ std::size_t shallow_size() const noexcept; DLocalSymtab * shallow_copy(obj mm) const noexcept; std::size_t forward_children(obj gc) noexcept; ///@} /** @defgroup xo-localsymtab-printable-facet printable facet **/ ///@{ bool pretty(const ppindentinfo & ppii) const; ///@} private: /** parent symbol table from scoping surrounding this one **/ DLocalSymtab * parent_ = nullptr; /** variables owned by (declared in) this symbol table * vars_[i] is convertible to obj **/ DArray * vars_ = nullptr; /** types owned by (defined in) this symbol table * types_[i] is convertible to obj **/ DArray * types_ = nullptr; #ifdef OBSOLETE /** actual range of slots_[] array. Can use indices in [0,..,n) **/ size_type capacity_ = 0; /** number of slots in use **/ size_type size_ = 0; /** memory for names and bindings **/ Slot slots_[]; #endif }; } /*namespace scm*/ } /*namespace xo*/ /* end DLocalSymtab.hpp */