mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
Merge ef018f57c8119331e03e1b6a2ed1a90570ee920c into 56506bc111ec6aa8dd3aed9dced23ef6a56b6c49
This commit is contained in:
commit
6e1c7510f1
@ -488,13 +488,17 @@ namespace chaiscript {
|
||||
false,
|
||||
*t_ss);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
// Value is not directly callable. Fall back to calling by name through the
|
||||
// dispatch engine, which handles the case where a global (e.g., class namespace)
|
||||
// shadows a function (e.g., constructor) with the same name.
|
||||
try {
|
||||
using ConstFunctionTypeRef = const Const_Proxy_Function &;
|
||||
Const_Proxy_Function f = t_ss->boxed_cast<ConstFunctionTypeRef>(fn);
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(f), false, *t_ss);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||
return t_ss->call_function(this->children[0]->text, m_loc, Function_Params{params}, t_ss.conversions());
|
||||
} catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'",
|
||||
e.parameters,
|
||||
e.functions,
|
||||
false,
|
||||
*t_ss);
|
||||
}
|
||||
} catch (const exception::arity_error &e) {
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||
@ -506,6 +510,9 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { return do_eval_internal<true>(t_ss); }
|
||||
|
||||
private:
|
||||
mutable std::atomic_uint_fast32_t m_loc = {0};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../dispatchkit/dynamic_object.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
@ -59,6 +60,25 @@ namespace chaiscript::utility {
|
||||
}
|
||||
}
|
||||
|
||||
/// Overload of add_class that also registers static functions accessible via ClassName.func() syntax.
|
||||
/// Static functions are exposed as attributes of a namespace object with the class name.
|
||||
template<typename Class, typename ModuleType>
|
||||
void add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<chaiscript::Proxy_Function> &t_constructors,
|
||||
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs,
|
||||
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_static_funcs) {
|
||||
add_class<Class>(t_module, t_class_name, t_constructors, t_funcs);
|
||||
|
||||
if (!t_static_funcs.empty()) {
|
||||
dispatch::Dynamic_Object ns(t_class_name);
|
||||
for (const auto &sf : t_static_funcs) {
|
||||
ns.get_attr(sf.second) = chaiscript::Boxed_Value(sf.first);
|
||||
}
|
||||
t_module.add_global_const(chaiscript::const_var(ns), t_class_name);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Enum, typename ModuleType>
|
||||
typename std::enable_if<std::is_enum<Enum>::value, void>::type
|
||||
add_class(ModuleType &t_module,
|
||||
|
||||
@ -555,6 +555,51 @@ TEST_CASE("Utility_Test utility class wrapper") {
|
||||
chai.eval("t = Utility_Test();");
|
||||
}
|
||||
|
||||
class Utility_Test_Static {
|
||||
public:
|
||||
Utility_Test_Static(int t_x, int t_y) : m_x(t_x), m_y(t_y) {}
|
||||
Utility_Test_Static() : m_x(0), m_y(0) {}
|
||||
|
||||
int area() const { return m_x * m_y; }
|
||||
|
||||
static int static_area(int t_x, int t_y) { return t_x * t_y; }
|
||||
static std::string name() { return "Utility_Test_Static"; }
|
||||
|
||||
int m_x;
|
||||
int m_y;
|
||||
};
|
||||
|
||||
TEST_CASE("Utility_Test add_class with static functions") {
|
||||
auto m = std::make_shared<chaiscript::Module>();
|
||||
|
||||
using namespace chaiscript;
|
||||
|
||||
chaiscript::utility::add_class<Utility_Test_Static>(
|
||||
*m,
|
||||
"UTS",
|
||||
{constructor<Utility_Test_Static()>(), constructor<Utility_Test_Static(int, int)>(),
|
||||
constructor<Utility_Test_Static(const Utility_Test_Static &)>()},
|
||||
{{fun(&Utility_Test_Static::area), "area"},
|
||||
{fun(&Utility_Test_Static::m_x), "x"},
|
||||
{fun(&Utility_Test_Static::m_y), "y"},
|
||||
{fun(static_cast<Utility_Test_Static &(Utility_Test_Static::*)(const Utility_Test_Static &)>(&Utility_Test_Static::operator=)), "="}},
|
||||
{{fun(&Utility_Test_Static::static_area), "area"},
|
||||
{fun(&Utility_Test_Static::name), "name"}});
|
||||
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
chai.add(m);
|
||||
|
||||
// Instance methods still work
|
||||
CHECK(chai.eval<int>("auto t = UTS(3, 4); t.area()") == 12);
|
||||
|
||||
// Static functions accessible via namespace dot syntax
|
||||
CHECK(chai.eval<int>("UTS.area(5, 6)") == 30);
|
||||
CHECK(chai.eval<std::string>("UTS.name()") == "Utility_Test_Static");
|
||||
|
||||
// Constructor still works alongside the namespace
|
||||
CHECK(chai.eval<int>("auto t2 = UTS(7, 8); t2.x") == 7);
|
||||
}
|
||||
|
||||
enum Utility_Test_Numbers {
|
||||
ONE,
|
||||
TWO,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user