Address review: snapshot top-level locals alongside engine state

ChaiScript::State captures globals, functions, and types but not the
top-level scripting locals created by `var x = ...`. The previous
restoreState therefore left such variables behind, breaking the
playground reset use case and tripping the new test's assertion in
Debug builds (where assert is enabled). Pair get_state with get_locals
in the snapshot so a restore brings back a clean baseline.

Requested by @lefticus in PR #699 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
leftibot 2026-04-30 17:03:00 -06:00
parent 810888defc
commit 34a95a28a0

View File

@ -12,6 +12,7 @@
#define CHAISCRIPT_EMSCRIPTEN_EVAL_HPP_
#include <chaiscript/chaiscript.hpp>
#include <map>
#include <string>
#include <unordered_map>
@ -21,8 +22,17 @@ namespace detail {
return chai;
}
inline std::unordered_map<int, chaiscript::ChaiScript::State> &state_registry() {
static std::unordered_map<int, chaiscript::ChaiScript::State> registry;
// ChaiScript::State captures globals/functions/types but not the top-level
// scripting locals (variables created by `var x = ...` at the script's
// outermost scope). The playground's reset-between-runs use case needs both,
// so the snapshot pairs the engine state with the locals map.
struct Snapshot {
chaiscript::ChaiScript::State engine_state;
std::map<std::string, chaiscript::Boxed_Value> locals;
};
inline std::unordered_map<int, Snapshot> &state_registry() {
static std::unordered_map<int, Snapshot> registry;
return registry;
}
@ -61,7 +71,8 @@ inline double chaiscript_eval_double(const std::string &input) {
// no longer needed.
inline int chaiscript_save_state() {
const int handle = detail::next_state_handle();
detail::state_registry().emplace(handle, detail::get_chai_instance().get_state());
auto &chai = detail::get_chai_instance();
detail::state_registry().emplace(handle, detail::Snapshot{chai.get_state(), chai.get_locals()});
return handle;
}
@ -70,7 +81,9 @@ inline int chaiscript_save_state() {
inline void chaiscript_restore_state(const int handle) {
const auto it = detail::state_registry().find(handle);
if (it != detail::state_registry().end()) {
detail::get_chai_instance().set_state(it->second);
auto &chai = detail::get_chai_instance();
chai.set_state(it->second.engine_state);
chai.set_locals(it->second.locals);
}
}