From a01687d7ad836c24621d8af26c08d760bae7eb0d Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Wed, 12 Oct 2016 09:38:50 -0500 Subject: [PATCH 01/10] Added basic namespace handling. The new code is wrapped in NAMESPACE HANDLING comments. C++: register_namespace(): registers a namespace with an instance of ChaiScript (supports delayed namespace generation) import(): imports a namespace as a global Dynamic_Object ChaiScript: import(): imports a namespace namespace(): generates and registers a new namespace --- .../chaiscript/language/chaiscript_engine.hpp | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 003af4e2..1033d770 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -50,6 +50,10 @@ namespace chaiscript { + // NAMESPACE HANLDING + // Namespace typedef to provide cleaner and more explicit syntax to users. + typedef dispatch::Dynamic_Object Namespace; + // END NAMESPACE HANDLING namespace detail { @@ -74,6 +78,19 @@ namespace chaiscript chaiscript::detail::Dispatch_Engine m_engine; + // NAMESPACE HANDLING + std::map m_namespaces; + std::map> m_namespace_generators; + + /// Helper function to add a namespace to the engine. + void add_namespace(const std::string& t_namespace_name) { + if (m_namespaces.count(t_namespace_name)) { + if (!m_engine.get_scripting_objects().count(t_namespace_name)) // Add namespace if it hasn't already been added. + m_engine.add_global(var(m_namespaces[t_namespace_name]), t_namespace_name); + } + } + // END NAMESPACE HANDLING + /// Evaluates the given string in by parsing it and running the results through the evaluator Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) { @@ -184,6 +201,11 @@ namespace chaiscript m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global"); + + // NAMESPACE HANDLING + m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace(t_namespace_name); import(t_namespace_name); }), "namespace"); + m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import"); + // END NAMESPACE HANDLING } @@ -694,6 +716,57 @@ namespace chaiscript T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) { return m_engine.boxed_cast(eval_file(t_filename, t_handler)); } + + // NAMESPACE HANDLING + /// \brief Imports a namespace object into the global scope of this ChaiScript instance. + void import(const std::string& t_namespace_name) + { + if (m_namespaces.count(t_namespace_name)) + add_namespace(t_namespace_name); + else if (m_namespace_generators.count(t_namespace_name)) { + m_namespace_generators[t_namespace_name](); + add_namespace(t_namespace_name); + } + else + throw std::runtime_error("No registered namespace: " + t_namespace_name); + } + + /// \brief Registers a new namespace with ChaiScript engine. + /// \throw std::runtime_error In the case that the namespace name was already registered. + void register_namespace(const std::string& t_namespace_name) { + if (!m_namespaces.count(t_namespace_name)) + m_namespaces.emplace(std::make_pair(t_namespace_name, dispatch::Dynamic_Object())); + else + throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } + + /// \brief Registers a new namespace with ChaiScript engine. + /// \throw std::runtime_error In the case that the namespace name was already registered. + void register_namespace(const dispatch::Dynamic_Object& namespace_object, const std::string& t_namespace_name) { + if (!m_namespaces.count(t_namespace_name)) + m_namespaces.emplace(std::make_pair(t_namespace_name, namespace_object)); + else + throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } + + /// \brief Registers a new namespace with ChaiScript engine. Permits move semantics. + /// \throw std::runtime_error In the case that the namespace name was already registered. + void register_namespace(dispatch::Dynamic_Object&& t_namespace_object, const std::string& t_namespace_name) { + if (!m_namespaces.count(t_namespace_name)) + m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); + } + + /// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used. + /// \throw std::runtime_error In the case that the namespace name was already registered. + void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) { + if (!m_namespaces.count(t_namespace_name)) { + std::function namespace_generator = [=]() { register_namespace(t_namespace_generator(), t_namespace_name); }; + m_namespace_generators.emplace(std::make_pair(t_namespace_name, namespace_generator)); + } + else + throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } + // END NAMESPACE HANDLING }; } From d2c2962eb7725b80958b9d4e5348be280dffba20 Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Mon, 17 Oct 2016 08:23:51 -0500 Subject: [PATCH 02/10] Added braces to better distinguish case statements. Added more comments to namespace handling functions. Added mutex protection to import. --- .../chaiscript/language/chaiscript_engine.hpp | 75 ++++++++++++------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 1033d770..fe484ca8 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -49,11 +49,9 @@ #include "../dispatchkit/exception_specification.hpp" namespace chaiscript -{ - // NAMESPACE HANLDING - // Namespace typedef to provide cleaner and more explicit syntax to users. - typedef dispatch::Dynamic_Object Namespace; - // END NAMESPACE HANDLING +{ + /// Namespace typedef to provide cleaner and more explicit syntax to users. + typedef dispatch::Dynamic_Object Namespace; namespace detail { @@ -78,18 +76,18 @@ namespace chaiscript chaiscript::detail::Dispatch_Engine m_engine; - // NAMESPACE HANDLING std::map m_namespaces; std::map> m_namespace_generators; /// Helper function to add a namespace to the engine. - void add_namespace(const std::string& t_namespace_name) { + void add_namespace(const std::string& t_namespace_name) + { if (m_namespaces.count(t_namespace_name)) { - if (!m_engine.get_scripting_objects().count(t_namespace_name)) // Add namespace if it hasn't already been added. + if (!m_engine.get_scripting_objects().count(t_namespace_name)) { // Add namespace if it hasn't already been added. m_engine.add_global(var(m_namespaces[t_namespace_name]), t_namespace_name); + } } - } - // END NAMESPACE HANDLING + } /// Evaluates the given string in by parsing it and running the results through the evaluator Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) @@ -202,10 +200,8 @@ namespace chaiscript m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global"); - // NAMESPACE HANDLING m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace(t_namespace_name); import(t_namespace_name); }), "namespace"); - m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import"); - // END NAMESPACE HANDLING + m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import"); } @@ -717,56 +713,77 @@ namespace chaiscript return m_engine.boxed_cast(eval_file(t_filename, t_handler)); } - // NAMESPACE HANDLING /// \brief Imports a namespace object into the global scope of this ChaiScript instance. + /// \param[in] t_namespace_name Name of the namespace to import. + /// \throw std::runtime_error In the case that the namespace name was never registered. void import(const std::string& t_namespace_name) { - if (m_namespaces.count(t_namespace_name)) + chaiscript::detail::threading::shared_lock l(m_mutex); + + if (m_namespaces.count(t_namespace_name)) { add_namespace(t_namespace_name); + } else if (m_namespace_generators.count(t_namespace_name)) { m_namespace_generators[t_namespace_name](); add_namespace(t_namespace_name); } - else + else { throw std::runtime_error("No registered namespace: " + t_namespace_name); + } } /// \brief Registers a new namespace with ChaiScript engine. + /// \param[in] t_namespace_name Name of the namespace to register. /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const std::string& t_namespace_name) { - if (!m_namespaces.count(t_namespace_name)) + void register_namespace(const std::string& t_namespace_name) + { + if (!m_namespaces.count(t_namespace_name)) { m_namespaces.emplace(std::make_pair(t_namespace_name, dispatch::Dynamic_Object())); - else + } + else { throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } } /// \brief Registers a new namespace with ChaiScript engine. + /// \param[in] t_namespace_object Namespace object to register. + /// \param[in] t_namespace_name Name of the Namespace object being registered. /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const dispatch::Dynamic_Object& namespace_object, const std::string& t_namespace_name) { - if (!m_namespaces.count(t_namespace_name)) - m_namespaces.emplace(std::make_pair(t_namespace_name, namespace_object)); - else + void register_namespace(const dispatch::Dynamic_Object& t_namespace_object, const std::string& t_namespace_name) + { + if (!m_namespaces.count(t_namespace_name)) { + m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); + } + else { throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } } /// \brief Registers a new namespace with ChaiScript engine. Permits move semantics. + /// \param[in] t_namespace_object Namespace object to register. + /// \param[in] t_namespace_name Name of the Namespace object being registered. /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(dispatch::Dynamic_Object&& t_namespace_object, const std::string& t_namespace_name) { - if (!m_namespaces.count(t_namespace_name)) + void register_namespace(dispatch::Dynamic_Object&& t_namespace_object, const std::string& t_namespace_name) + { + if (!m_namespaces.count(t_namespace_name)) { m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); + } } /// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used. + /// \param[in] t_namespace_generator Namespace generator function. + /// \param[in] t_namespace_name Name of the Namespace function being registered. /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) { + void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) + { if (!m_namespaces.count(t_namespace_name)) { std::function namespace_generator = [=]() { register_namespace(t_namespace_generator(), t_namespace_name); }; m_namespace_generators.emplace(std::make_pair(t_namespace_name, namespace_generator)); } - else + else { throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); - } - // END NAMESPACE HANDLING + } + } }; } From d61e322c1d14ebf8fa507bc397721b76c10f32e9 Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 18 Oct 2016 08:53:37 -0500 Subject: [PATCH 03/10] Added unit tests for namespaces. These demonstrate the global scope of namespaces, defining functions and variables within namespaces, and namespace nesting by copy or reference. --- unittests/namespaces.chai | 7 +++++++ unittests/namespaces_nested_copy.chai | 9 +++++++++ unittests/namespaces_nested_ref.chai | 9 +++++++++ 3 files changed, 25 insertions(+) create mode 100644 unittests/namespaces.chai create mode 100644 unittests/namespaces_nested_copy.chai create mode 100644 unittests/namespaces_nested_ref.chai diff --git a/unittests/namespaces.chai b/unittests/namespaces.chai new file mode 100644 index 00000000..51bea60f --- /dev/null +++ b/unittests/namespaces.chai @@ -0,0 +1,7 @@ +namespace("math") + +math.square = fun(x) { x * x } +math.sum_squares = fun(x, y) { math.square(x) + math.square(y) } + +assert_equal(16, math.square(4)) +assert_equal(29, math.sum_squares(2, 5)) \ No newline at end of file diff --git a/unittests/namespaces_nested_copy.chai b/unittests/namespaces_nested_copy.chai new file mode 100644 index 00000000..7ec8ff53 --- /dev/null +++ b/unittests/namespaces_nested_copy.chai @@ -0,0 +1,9 @@ +namespace("parent") +namespace("child") + +child.x = 3.0 +parent.child = child +parent.child.x = 5.0 + +assert_equal(3.0, child.x) +assert_equal(5.0, parent.child.x) \ No newline at end of file diff --git a/unittests/namespaces_nested_ref.chai b/unittests/namespaces_nested_ref.chai new file mode 100644 index 00000000..5be991cb --- /dev/null +++ b/unittests/namespaces_nested_ref.chai @@ -0,0 +1,9 @@ +namespace("parent") +namespace("child") + +child.x = 3.0 +parent.child := child +parent.child.x = 5.0 + +assert_equal(5.0, child.x) +assert_equal(5.0, parent.child.x) \ No newline at end of file From c45be80bf5e5986a878957e28d564d639cc2643f Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 18 Oct 2016 09:26:28 -0500 Subject: [PATCH 04/10] Added namespace documentation to the cheatsheet.md --- cheatsheet.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cheatsheet.md b/cheatsheet.md index ab85c167..ea65ca61 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -119,6 +119,18 @@ chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throw chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object ``` +## Adding Namespaces + +``` +chaiscript::Namespace math; +math["pi"] = chaiscript::const_var(3.14159); +math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); +chai.register_namespace(math, "math"); +``` + +Namespaces are imported to make them available for scripting +``` + # Using STL ChaiScript recognize many types from STL, but you have to add specific instantiation yourself. @@ -423,6 +435,20 @@ o.f = fun(y) { print(this.x + y); } o.f(10); // prints 13 ``` +## Namespaces + +Namespaces in ChaiScript are Dynamic Objects with global scope + +``` +namespace("math") // create a new namespace + +math.square = fun(x) { x * x } // add a function to the "math" namespace +math.sum_squares = fun(x, y) { math.square(x) + math.square(y) } + +print(math.square(4)) // prints 16 +print(math.sum_squares(2, 5)) // prints 29 +``` + ### Option Explicit If you want to disable dynamic parameter definitions, you can `set_explicit`. From 96d2eddce1e2374ed53c18b16949505923c2681f Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 18 Oct 2016 09:29:14 -0500 Subject: [PATCH 05/10] Fixing cheatsheet.md namespace documentation --- cheatsheet.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cheatsheet.md b/cheatsheet.md index ea65ca61..ab2d8e33 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -129,6 +129,27 @@ chai.register_namespace(math, "math"); ``` Namespaces are imported to make them available for scripting + +``` +chai.import("math"); // importing via C++ (_not generally recommended_) +``` + +``` +import("math") // importing via ChaiScript (_recommended_) +print(math.pi) // prints 3.14159 +``` + +### Delayed Namespace Generation + +Passing a lambda function that returns a namespace will delay the namespace generation until `import` is called. +This saves memory and computing costs if a namespace is not imported into every ChaiScript instance. +``` +chai.register_namespace([]() { + chaiscript::Namespace math; + math["pi"] = chaiscript::const_var(3.14159); + math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); + return math; }, + "math"); ``` # Using STL From 9f1ba21c5ebd80c1442c7ecc4d038f9bd77fda0b Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 18 Oct 2016 09:34:45 -0500 Subject: [PATCH 06/10] Cleaning up namespace documentation --- cheatsheet.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cheatsheet.md b/cheatsheet.md index ab2d8e33..4fe33ff8 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -130,16 +130,18 @@ chai.register_namespace(math, "math"); Namespaces are imported to make them available for scripting +Importing via C++ (_not generally recommended_) ``` -chai.import("math"); // importing via C++ (_not generally recommended_) +chai.import("math"); ``` +Importing via ChaiScript (recommended) ``` -import("math") // importing via ChaiScript (_recommended_) +import("math") print(math.pi) // prints 3.14159 ``` -### Delayed Namespace Generation +#### Delayed Namespace Generation Passing a lambda function that returns a namespace will delay the namespace generation until `import` is called. This saves memory and computing costs if a namespace is not imported into every ChaiScript instance. From 08abf41dfbf08342398405649d901306dd8974d4 Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 18 Oct 2016 09:37:41 -0500 Subject: [PATCH 07/10] Another cheatsheet.md namespace update --- cheatsheet.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cheatsheet.md b/cheatsheet.md index 4fe33ff8..cbc78bfa 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -128,14 +128,12 @@ math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x) chai.register_namespace(math, "math"); ``` -Namespaces are imported to make them available for scripting - -Importing via C++ (_not generally recommended_) +Import namespace via C++ (_not generally recommended_) ``` chai.import("math"); ``` -Importing via ChaiScript (recommended) +Import namespace via ChaiScript (_recommended_) ``` import("math") print(math.pi) // prints 3.14159 From 3f299333ccfd4124746ce87e763679d7698c0434 Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 5 Sep 2017 12:01:37 -0500 Subject: [PATCH 08/10] Switched to recursive mutex Removed namespaces_nested_ref.chai --- include/chaiscript/language/chaiscript_engine.hpp | 13 ++++++++++++- unittests/namespaces_nested_ref.chai | 9 --------- 2 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 unittests/namespaces_nested_ref.chai diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index fe484ca8..6a96f132 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -718,7 +718,7 @@ namespace chaiscript /// \throw std::runtime_error In the case that the namespace name was never registered. void import(const std::string& t_namespace_name) { - chaiscript::detail::threading::shared_lock l(m_mutex); + chaiscript::detail::threading::unique_lock l(m_use_mutex); if (m_namespaces.count(t_namespace_name)) { add_namespace(t_namespace_name); @@ -737,6 +737,8 @@ namespace chaiscript /// \throw std::runtime_error In the case that the namespace name was already registered. void register_namespace(const std::string& t_namespace_name) { + chaiscript::detail::threading::unique_lock l(m_use_mutex); + if (!m_namespaces.count(t_namespace_name)) { m_namespaces.emplace(std::make_pair(t_namespace_name, dispatch::Dynamic_Object())); } @@ -751,6 +753,8 @@ namespace chaiscript /// \throw std::runtime_error In the case that the namespace name was already registered. void register_namespace(const dispatch::Dynamic_Object& t_namespace_object, const std::string& t_namespace_name) { + chaiscript::detail::threading::unique_lock l(m_use_mutex); + if (!m_namespaces.count(t_namespace_name)) { m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); } @@ -765,9 +769,14 @@ namespace chaiscript /// \throw std::runtime_error In the case that the namespace name was already registered. void register_namespace(dispatch::Dynamic_Object&& t_namespace_object, const std::string& t_namespace_name) { + chaiscript::detail::threading::unique_lock l(m_use_mutex); + if (!m_namespaces.count(t_namespace_name)) { m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); } + else { + throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } } /// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used. @@ -776,6 +785,8 @@ namespace chaiscript /// \throw std::runtime_error In the case that the namespace name was already registered. void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) { + chaiscript::detail::threading::unique_lock l(m_use_mutex); + if (!m_namespaces.count(t_namespace_name)) { std::function namespace_generator = [=]() { register_namespace(t_namespace_generator(), t_namespace_name); }; m_namespace_generators.emplace(std::make_pair(t_namespace_name, namespace_generator)); diff --git a/unittests/namespaces_nested_ref.chai b/unittests/namespaces_nested_ref.chai deleted file mode 100644 index 5be991cb..00000000 --- a/unittests/namespaces_nested_ref.chai +++ /dev/null @@ -1,9 +0,0 @@ -namespace("parent") -namespace("child") - -child.x = 3.0 -parent.child := child -parent.child.x = 5.0 - -assert_equal(5.0, child.x) -assert_equal(5.0, parent.child.x) \ No newline at end of file From ff78d315835500c97dd2126d26dc3f4431100309 Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 5 Sep 2017 13:25:41 -0500 Subject: [PATCH 09/10] Simplified namespace handling code and requiring all namespace registration to allow for delayed generation. This simplifies generating namespaces by the user and leads to more efficient code. --- .../chaiscript/language/chaiscript_engine.hpp | 81 +++---------------- 1 file changed, 11 insertions(+), 70 deletions(-) diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index e24a6c7e..ed3b1141 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -55,8 +55,8 @@ namespace chaiscript { - /// Namespace typedef to provide cleaner and more explicit syntax to users. - typedef dispatch::Dynamic_Object Namespace; + /// Namespace alias to provide cleaner and more explicit syntax to users. + using Namespace = dispatch::Dynamic_Object; namespace detail { @@ -81,18 +81,7 @@ namespace chaiscript chaiscript::detail::Dispatch_Engine m_engine; - std::map m_namespaces; - std::map> m_namespace_generators; - - /// Helper function to add a namespace to the engine. - void add_namespace(const std::string& t_namespace_name) - { - if (m_namespaces.count(t_namespace_name)) { - if (!m_engine.get_scripting_objects().count(t_namespace_name)) { // Add namespace if it hasn't already been added. - m_engine.add_global(var(m_namespaces[t_namespace_name]), t_namespace_name); - } - } - } + std::map> m_namespace_generators; /// Evaluates the given string in by parsing it and running the results through the evaluator Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) @@ -211,7 +200,7 @@ namespace chaiscript m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global"); - m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace(t_namespace_name); import(t_namespace_name); }), "namespace"); + m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& space) {}, t_namespace_name); import(t_namespace_name); }), "namespace"); m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import"); } @@ -729,76 +718,28 @@ explicit ChaiScript_Basic(std::unique_ptr &&pars { chaiscript::detail::threading::unique_lock l(m_use_mutex); - if (m_namespaces.count(t_namespace_name)) { - add_namespace(t_namespace_name); + if (m_engine.get_scripting_objects().count(t_namespace_name)) { + throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined"); } else if (m_namespace_generators.count(t_namespace_name)) { - m_namespace_generators[t_namespace_name](); - add_namespace(t_namespace_name); + m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name); } else { throw std::runtime_error("No registered namespace: " + t_namespace_name); } } - /// \brief Registers a new namespace with ChaiScript engine. - /// \param[in] t_namespace_name Name of the namespace to register. - /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const std::string& t_namespace_name) - { - chaiscript::detail::threading::unique_lock l(m_use_mutex); - - if (!m_namespaces.count(t_namespace_name)) { - m_namespaces.emplace(std::make_pair(t_namespace_name, dispatch::Dynamic_Object())); - } - else { - throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); - } - } - - /// \brief Registers a new namespace with ChaiScript engine. - /// \param[in] t_namespace_object Namespace object to register. - /// \param[in] t_namespace_name Name of the Namespace object being registered. - /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const dispatch::Dynamic_Object& t_namespace_object, const std::string& t_namespace_name) - { - chaiscript::detail::threading::unique_lock l(m_use_mutex); - - if (!m_namespaces.count(t_namespace_name)) { - m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); - } - else { - throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); - } - } - - /// \brief Registers a new namespace with ChaiScript engine. Permits move semantics. - /// \param[in] t_namespace_object Namespace object to register. - /// \param[in] t_namespace_name Name of the Namespace object being registered. - /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(dispatch::Dynamic_Object&& t_namespace_object, const std::string& t_namespace_name) - { - chaiscript::detail::threading::unique_lock l(m_use_mutex); - - if (!m_namespaces.count(t_namespace_name)) { - m_namespaces.emplace(std::make_pair(t_namespace_name, t_namespace_object)); - } - else { - throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); - } - } - /// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used. /// \param[in] t_namespace_generator Namespace generator function. /// \param[in] t_namespace_name Name of the Namespace function being registered. /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) + void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) { chaiscript::detail::threading::unique_lock l(m_use_mutex); - if (!m_namespaces.count(t_namespace_name)) { - std::function namespace_generator = [=]() { register_namespace(t_namespace_generator(), t_namespace_name); }; - m_namespace_generators.emplace(std::make_pair(t_namespace_name, namespace_generator)); + if (!m_namespace_generators.count(t_namespace_name)) { + // contain the namespace object memory within the m_namespace_generators map + m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace& { t_namespace_generator(space); return space; })); } else { throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); From 037faddab4810fdb845aa3a3f12ec20e10cd3197 Mon Sep 17 00:00:00 2001 From: Stephen Berry Date: Tue, 5 Sep 2017 13:47:53 -0500 Subject: [PATCH 10/10] Updated cheatsheet.md for latest namespace implementation --- cheatsheet.md | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/cheatsheet.md b/cheatsheet.md index f25107c0..28debbca 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -168,37 +168,21 @@ chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overw ## Adding Namespaces +Namespaces will not be populated until `import` is called. +This saves memory and computing costs if a namespace is not imported into every ChaiScript instance. ``` -chaiscript::Namespace math; -math["pi"] = chaiscript::const_var(3.14159); -math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); -chai.register_namespace(math, "math"); +chai.register_namespace([](chaiscript::Namespace& math) { + math["pi"] = chaiscript::const_var(3.14159); + math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); }, + "math"); ``` -Import namespace via C++ (_not generally recommended_) -``` -chai.import("math"); -``` - -Import namespace via ChaiScript (_recommended_) +Import namespace in ChaiScript ``` import("math") print(math.pi) // prints 3.14159 ``` -#### Delayed Namespace Generation - -Passing a lambda function that returns a namespace will delay the namespace generation until `import` is called. -This saves memory and computing costs if a namespace is not imported into every ChaiScript instance. -``` -chai.register_namespace([]() { - chaiscript::Namespace math; - math["pi"] = chaiscript::const_var(3.14159); - math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); - return math; }, - "math"); -``` - # Using STL ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.