mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2025-12-06 16:57:04 +08:00
Merge remote-tracking branch 'origin/develop' into best_practices
This commit is contained in:
commit
6ae3f2d187
@ -166,6 +166,23 @@ 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
|
||||
|
||||
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.
|
||||
```
|
||||
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 in ChaiScript
|
||||
```
|
||||
import("math")
|
||||
print(math.pi) // prints 3.14159
|
||||
```
|
||||
|
||||
# Using STL
|
||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||
|
||||
@ -479,6 +496,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`.
|
||||
|
||||
@ -54,7 +54,9 @@
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
{
|
||||
/// Namespace alias to provide cleaner and more explicit syntax to users.
|
||||
using Namespace = dispatch::Dynamic_Object;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@ -79,6 +81,8 @@ namespace chaiscript
|
||||
|
||||
chaiscript::detail::Dispatch_Engine m_engine;
|
||||
|
||||
std::map<std::string, std::function<Namespace&()>> 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)
|
||||
{
|
||||
@ -195,6 +199,9 @@ 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");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
@ -702,6 +709,41 @@ namespace chaiscript
|
||||
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
||||
}
|
||||
|
||||
/// \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)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
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_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 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<void(Namespace&)>& t_namespace_generator, const std::string& t_namespace_name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
7
unittests/namespaces.chai
Normal file
7
unittests/namespaces.chai
Normal file
@ -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))
|
||||
9
unittests/namespaces_nested_copy.chai
Normal file
9
unittests/namespaces_nested_copy.chai
Normal file
@ -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)
|
||||
Loading…
x
Reference in New Issue
Block a user