From 03847102befed6e0319ca53bb7a334ce394b0679 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 16 Feb 2026 19:48:14 -0500 Subject: [PATCH] xo-expression2: upsert global vars works in DDefineSsm --- include/xo/expression2/DGlobalSymtab.hpp | 11 ++- include/xo/expression2/DVariable.hpp | 1 + src/expression2/DGlobalSymtab.cpp | 94 +++++++++++++++--------- 3 files changed, 67 insertions(+), 39 deletions(-) diff --git a/include/xo/expression2/DGlobalSymtab.hpp b/include/xo/expression2/DGlobalSymtab.hpp index 6ae8895b..63a2a91f 100644 --- a/include/xo/expression2/DGlobalSymtab.hpp +++ b/include/xo/expression2/DGlobalSymtab.hpp @@ -65,13 +65,12 @@ namespace xo { /** @defgroup scm-globalsymtab-general-methods general methods **/ ///@{ - /** establish binding for @p sym, with type described by @p typeref, - * replacing existing global (if present) with the same name. - * Use memory from @p mm to create variable-expr + /** update this symtab to associate @p var with @c var->name(). + * If there was a previous variable with the same name, + * replace it with @p var. **/ - DVariable * establish_variable(obj mm, - const DUniqueString * sym, - TypeRef typeref); + void upsert_variable(obj mm, + DVariable * var); ///@} /** @defgroup scm-globalsymtab-symboltable-facet symboltable facet **/ diff --git a/include/xo/expression2/DVariable.hpp b/include/xo/expression2/DVariable.hpp index 3c89cc58..29253097 100644 --- a/include/xo/expression2/DVariable.hpp +++ b/include/xo/expression2/DVariable.hpp @@ -48,6 +48,7 @@ namespace xo { Binding path() const { return path_; } void assign_name(const DUniqueString * name) { this->name_ = name; } + void assign_path(Binding b) { this->path_ = b; } /** @defgroup scm-variable-expression-facet **/ ///@{ diff --git a/src/expression2/DGlobalSymtab.cpp b/src/expression2/DGlobalSymtab.cpp index 70b953dd..89d10f32 100644 --- a/src/expression2/DGlobalSymtab.cpp +++ b/src/expression2/DGlobalSymtab.cpp @@ -65,6 +65,65 @@ namespace xo { return var.data(); } + void + DGlobalSymtab::upsert_variable(obj mm, + DVariable * var) + { + // It's possible there's already a global variable + // with the same name. + // + // For example redefining a variable in an interactive session. + // In this case use the established binding. + // + DVariable * existing = this->lookup_variable(var->name()); + + if (existing) { + if (existing == var) { + // impossible, but.. noop, right? + return; + } + + // adopt the existing binding + var->assign_path(existing->path()); + + // stash new definition (possibly has different type), + // replacing previous one + // + (*vars_)[existing->path().j_slot()] = obj(var); + } else { + DArray::size_type n = vars_->size(); + + // NOTE: expansion of var_ array here is moot at present (Feb 2026), + // since the feature isn't yet implemented in ArenaHashMap + + /** make sure vars_ has room **/ + if (n == vars_->capacity()) { + // DArray is out of room. Reallocate with more capacity + DArray * vars_2x = DArray::copy(mm, vars_, vars_->capacity() * 2); + + if (!vars_2x) { + assert(false); + + // in any case, we can't make progress + return; + } + + this->vars_ = vars_2x; + } + + /** now we know binding for var **/ + Binding binding = Binding::global(n); + + var->assign_path(binding); + + // need slot# in .map_ for this unique symbol + (*map_)[var->name()] = binding.j_slot(); + + vars_->push_back(obj(var)); + } + } + +#ifdef NOT_USING // don't know if we need this path DVariable * DGlobalSymtab::establish_variable(obj mm, const DUniqueString * sym, @@ -75,43 +134,12 @@ namespace xo { if (!var) { assert(vars_); - DArray::size_type n = vars_->size(); - - // NOTE: expansion here is moot at present (Feb 2026). - // Not implemented in ArenaHashMap - - /** make sure vars_ has room **/ - if (n == vars_->capacity()) { - // reallocate with more capacity - DArray * vars_2x = DArray::copy(mm, vars_, vars_->capacity() * 2); - - assert(vars_2x); - - this->vars_ = vars_2x; - } - - /** create new variable **/ - Binding binding = Binding::global(n); - var = DVariable::make(mm, sym, typeref, binding); - - if (!var) { - // something terribly wrong - assert(false); - return var; - } - - assert(map_->size() < map_->capacity()); - - (*map_)[sym] = binding.j_slot(); - - bool ok = vars_->push_back(obj(var)); - - if (!ok) - assert(false); + xxx; } return var; } +#endif Binding DGlobalSymtab::lookup_binding(const DUniqueString * sym) const noexcept