From 4ab3a8499b602e2f3d0dd7f7c5e23c825a73cd7c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 28 Jul 2025 13:16:09 -0400 Subject: [PATCH] xo-expression: generalize envframestack + handle explicit lm retturn --- include/xo/expression/Environment.hpp | 16 ++++++++++++ include/xo/expression/GlobalEnv.hpp | 10 ++++++-- include/xo/expression/LocalEnv.hpp | 37 +++++++++++++++++---------- src/expression/GlobalEnv.cpp | 8 ++++++ src/expression/LocalEnv.cpp | 15 +---------- 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/include/xo/expression/Environment.hpp b/include/xo/expression/Environment.hpp index 51746d99..f3f482e4 100644 --- a/include/xo/expression/Environment.hpp +++ b/include/xo/expression/Environment.hpp @@ -6,6 +6,7 @@ #pragma once #include "xo/refcnt/Refcounted.hpp" +#include "Variable.hpp" #include "binding_path.hpp" #include "xo/indentlog/print/pretty.hpp" @@ -14,6 +15,13 @@ namespace xo { namespace scm { class Expression; + /** @class Environment + * @brief Abstract interface for tracking variable bindings + * + * When parsing (see xo-reader): rhs will always be a variable. + * When generating code (see xo-jit): rhs can be any expression, + * for example a Lambda. + **/ class Environment : public ref::Refcount { public: /** true if this is toplevel (global) environment. @@ -36,6 +44,14 @@ namespace xo { **/ virtual bp lookup_var(const std::string & vname) const = 0; + /** like @ref lookup_var but do not delegate to parent environment **/ + virtual bp lookup_local(const std::string & vname) const = 0; + + /** create/replace local variable @p target. + * Narrow use case: intended for when Environment represents a top-level session environment + **/ + virtual void upsert_local(bp target) = 0; + virtual void print(std::ostream & os) const = 0; virtual std::uint32_t pretty_print(const xo::print::ppindentinfo & ppii) const = 0; }; diff --git a/include/xo/expression/GlobalEnv.hpp b/include/xo/expression/GlobalEnv.hpp index b9cc026e..2670f929 100644 --- a/include/xo/expression/GlobalEnv.hpp +++ b/include/xo/expression/GlobalEnv.hpp @@ -14,7 +14,7 @@ namespace xo { class GlobalEnv : public Environment { public: /** create instance. Probably only need one of these **/ - static rp make() { return new GlobalEnv(); } + static rp make_empty() { return new GlobalEnv(); } bp require_global(const std::string & vname, bp expr); @@ -31,16 +31,22 @@ namespace xo { } virtual bp lookup_var(const std::string & vname) const override { + return this->lookup_local(vname); + } + + virtual bp lookup_local(const std::string & vname) const override { auto ix = global_map_.find(vname); if (ix == global_map_.end()) { /* not found */ - return bp::from_native(nullptr); + return bp::from_native(nullptr); } return ix->second; } + virtual void upsert_local(bp target) override; + virtual void print(std::ostream & os) const override; virtual std::uint32_t pretty_print(const xo::print::ppindentinfo & ppii) const override; diff --git a/include/xo/expression/LocalEnv.hpp b/include/xo/expression/LocalEnv.hpp index ea4e7e0a..dc500f37 100644 --- a/include/xo/expression/LocalEnv.hpp +++ b/include/xo/expression/LocalEnv.hpp @@ -32,6 +32,8 @@ namespace xo { /** Create instance with single local variable @ap argv1 **/ static rp make1(const rp & arg1, const rp & parent_env); + /** runtime downcast. nullptr if @p x is not a LocalEnv instance **/ + static bp from(const bp & x) { return bp::from(x); } Lambda * origin() const { return origin_; } const std::vector> & argv() const { return argv_; } @@ -53,31 +55,38 @@ namespace xo { /** single-assign this environment's parent **/ void assign_parent(bp p); - /** create/replace local variable @p target. - * Narrow use case: intended for when LocalEnv represents a top-level session environment - **/ - void upsert_local(bp target); - - bp lookup_local(const std::string & vname) const; - // ----- Environment ----- virtual bool is_global_env() const override { return false; } virtual binding_path lookup_binding(const std::string & vname) const override; - virtual bp lookup_var(const std::string & target) const override { - for (const auto & arg : argv_) { - if (arg->name() == target) - return arg; - } + virtual bp lookup_var(const std::string & vname) const override { + bp retval = this->lookup_local(vname); + + if (retval) + return retval; /* here: target not found in local vars, * delegate to innermost ancestor */ - return parent_env_->lookup_var(target); + return parent_env_->lookup_var(vname); } + virtual bp lookup_local(const std::string & vname) const override { + for (const auto & arg : argv_) { + if (arg->name() == vname) + return arg; + } + + return bp(); + } + + /** create/replace local variable @p target. + * Narrow use case: intended for when LocalEnv represents a top-level session environment. + **/ + virtual void upsert_local(bp target) override; + virtual void print(std::ostream & os) const override; virtual std::uint32_t pretty_print(const print::ppindentinfo & ppii) const override; @@ -85,7 +94,7 @@ namespace xo { LocalEnv(const std::vector> & argv, const rp & parent_env); private: - /** Lambnda for which this environment created. + /** Lambda for which this environment created. * * Invariant: * @code diff --git a/src/expression/GlobalEnv.cpp b/src/expression/GlobalEnv.cpp index 23962fd0..14e9a4e8 100644 --- a/src/expression/GlobalEnv.cpp +++ b/src/expression/GlobalEnv.cpp @@ -16,9 +16,17 @@ namespace xo { bp expr) { this->global_map_[vname] = expr.get(); + return expr; } /*require_global*/ + void + GlobalEnv::upsert_local(bp target) { + // in practice: paraphrase of .require_global() + + this->global_map_[target->name()] = target.promote(); + } + void GlobalEnv::print(std::ostream & os) const { os << " - LocalEnv::lookup_local(const std::string & vname) const { - for (const auto & var : this->argv_) { - if (var->name() == vname) - return var; - } - - return bp::from_native(nullptr); - } - void LocalEnv::assign_parent(bp p) { if ((parent_env_.get() != nullptr) && (parent_env_.get() != p.get())) { @@ -110,8 +100,7 @@ namespace xo { void LocalEnv::print(std::ostream& os) const { - os << ""; } @@ -125,8 +114,6 @@ namespace xo { if (ppii.upto()) { if (!pps->print_upto("print_upto_tag("this", (void*)this)) - return false; if (!pps->print_upto_tag("argv", argv_)) return false; pps->write(">");