diff --git a/CMakeLists.txt b/CMakeLists.txt index 5674bae..08029b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,6 +196,10 @@ if(BUILD_TESTING) target_link_libraries(expected_eval_errors_test ${LIBS}) add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test) + add_executable(set_state_test unittests/set_state_test.cpp) + target_link_libraries(set_state_test ${LIBS}) + add_test(NAME Set_State_Test COMMAND set_state_test) + if (MULTITHREAD_SUPPORT_ENABLED) add_executable(multithreaded_test unittests/multithreaded_test.cpp) target_link_libraries(multithreaded_test ${LIBS}) diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 4f97996..47ba903 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -140,7 +140,10 @@ /// /// \subsubsection addingobjects Adding Objects /// -/// Named objects can be created with the chaiscript::var function. +/// Named objects can be created with the chaiscript::var function. Note: adding a object +/// adds it to the current thread scope, not to a global scope. If you have multiple +/// threads that need to access the same variables you will need to add them +/// separately for each thread, from the thread itself. /// /// \code /// using namespace chaiscript; diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 89508d1..a5c68f2 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -666,6 +666,27 @@ namespace chaiscript return functions.find(name) != functions.end(); } + /// \returns All values in the local thread state, added through the add() function + std::map get_locals() const + { + StackData &stack = get_stack_data(); + Scope &scope = stack.front(); + return scope; + } + + /// \brief Sets all of the locals for the current thread state. + /// + /// \param[in] t_locals The map set of variables to replace the current state with + /// + /// Any existing locals are removed and the given set of variables is added + void set_locals(const std::map &t_locals) + { + StackData &stack = get_stack_data(); + Scope &scope = stack.front(); + scope = t_locals; + } + + /// /// Get a map of all objects that can be seen from the current scope in a scripting context diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 2539fa9..e526c8d 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -456,8 +456,12 @@ namespace chaiscript std::set active_loaded_modules; }; - /// \brief Returns a state object that represents the current state of the system - /// \return Current state of the system + /// \brief Returns a state object that represents the current state of the global system + /// + /// The global system includes the reserved words, global const objects, functions and types. + /// local variables are thread specific and not included. + /// + /// \return Current state of the global system /// /// \b Example: /// @@ -478,6 +482,10 @@ namespace chaiscript } /// \brief Sets the state of the system + /// + /// The global system includes the reserved words, global objects, functions and types. + /// local variables are thread specific and not included. + /// /// \param[in] t_state New state to set /// /// \b Example: @@ -497,7 +505,23 @@ namespace chaiscript m_engine.set_state(t_state.engine_state); } - /// \brief Adds a type, function or object to ChaiScript + /// \returns All values in the local thread state, added through the add() function + std::map get_locals() const + { + return m_engine.get_locals(); + } + + /// \brief Sets all of the locals for the current thread state. + /// + /// \param[in] t_locals The map set of variables to replace the current state with + /// + /// Any existing locals are removed and the given set of variables is added + void set_locals(const std::map &t_locals) + { + m_engine.set_locals(t_locals); + } + + /// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state. /// \param[in] t_t Item to add /// \param[in] t_name Name of item to add /// \returns Reference to current ChaiScript object diff --git a/unittests/set_state_test.cpp b/unittests/set_state_test.cpp new file mode 100644 index 0000000..5c745b9 --- /dev/null +++ b/unittests/set_state_test.cpp @@ -0,0 +1,61 @@ +#include + + +int myfun() +{ + return 2; +} + +int main() +{ + + chaiscript::ChaiScript chai; + + // save the initial state of globals and locals + chaiscript::ChaiScript::State firststate = chai.get_state(); + std::map locals = chai.get_locals(); + + // add some new globals and locals + chai.add(chaiscript::var(1), "i"); + + chai.add(chaiscript::fun(&myfun), "myfun"); + + + bool didcall = chai.eval("myfun()") == 2; + + bool hadi = chai.eval("i") == 1; + + chai.set_state(firststate); + + // set state should have reverted the state of the functions and dropped + // the 'myfun' + bool didnotcall = false; + + try { + chai.eval("myfun()"); + } catch (const chaiscript::exception::eval_error &) { + didnotcall = true; + } + + // set state should not affect the local variables + bool stillhasid = chai.eval("i") == 1; + + // After resetting the locals we expect the 'i' to be gone + chai.set_locals(locals); + + + bool nolongerhasid = false; + + try { + chai.eval("i"); + } catch (const chaiscript::exception::eval_error &) { + nolongerhasid = true; + } + + if (didcall && hadi && didnotcall && stillhasid && nolongerhasid) + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +}