diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index d8df9be..2e08777 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -33,14 +33,14 @@ namespace chaiscript template struct Cast_Helper_Inner { - typedef std::reference_wrapper::type > Result_Type; + typedef typename std::add_const::type Result_Type; static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { auto p = throw_if_null(ob.get_const_ptr()); - return std::cref(*static_cast(p)); + return *static_cast(p); } else { throw chaiscript::detail::exception::bad_any_cast(); } @@ -52,12 +52,6 @@ namespace chaiscript { }; - /// Cast_Helper_Inner for casting to a const & type - template - struct Cast_Helper_Inner : Cast_Helper_Inner - { - }; - /// Cast_Helper_Inner for casting to a const * type template @@ -68,7 +62,7 @@ namespace chaiscript { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { - return static_cast(throw_if_null(ob.get_const_ptr())); + return static_cast(ob.get_const_ptr()); } else { throw chaiscript::detail::exception::bad_any_cast(); } @@ -84,7 +78,36 @@ namespace chaiscript { if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result)) { - return static_cast(throw_if_null(ob.get_ptr())); + return static_cast(ob.get_ptr()); + } else { + throw chaiscript::detail::exception::bad_any_cast(); + } + } + }; + + template + struct Cast_Helper_Inner : public Cast_Helper_Inner + { + }; + + template + struct Cast_Helper_Inner : public Cast_Helper_Inner + { + }; + + + /// Cast_Helper_Inner for casting to a & type + template + struct Cast_Helper_Inner + { + typedef const Result& Result_Type; + + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) + { + if (ob.get_type_info().bare_equal_type_info(typeid(Result))) + { + auto p = throw_if_null(ob.get_const_ptr()); + return *static_cast(p); } else { throw chaiscript::detail::exception::bad_any_cast(); } diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index ecd5a3f..381afda 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -8,12 +8,14 @@ #define CHAISCRIPT_UTILITY_UTILITY_HPP_ #include +#include #include #include #include "../chaiscript.hpp" #include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/type_info.hpp" +#include "../dispatchkit/operators.hpp" namespace chaiscript @@ -62,6 +64,32 @@ namespace chaiscript t_module.add(fun.first, fun.second); } } + + template + typename std::enable_if::value, void>::type + add_class(ModuleType &t_module, + const std::string &t_class_name, + const std::vector::type, std::string>> &t_constants) + { + t_module.add(chaiscript::user_type(), t_class_name); + + t_module.add(chaiscript::constructor(), t_class_name); + t_module.add(chaiscript::constructor(), t_class_name); + + t_module.add([](){ + // add some comparison and assignment operators + using namespace chaiscript::bootstrap::operators; + return assign(not_equal(equal())); + }()); + + t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type::type &i) { return e == i; }), "=="); + t_module.add(chaiscript::fun([](const typename std::underlying_type::type &i, const Enum &e) { return i == e; }), "=="); + + for (const auto &constant : t_constants) + { + t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); + } + } } } diff --git a/unittests/boxed_cast_test.cpp b/unittests/boxed_cast_test.cpp index e575649..1e92874 100644 --- a/unittests/boxed_cast_test.cpp +++ b/unittests/boxed_cast_test.cpp @@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) try { To ret = chaiscript::boxed_cast(bv); use(ret); - } catch (const chaiscript::exception::bad_boxed_cast &/*e*/) { + } catch (const chaiscript::exception::bad_boxed_cast &e) { if (expectedpass) { -// std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n'; + std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n'; return false; } else { return true; diff --git a/unittests/compiled_tests.cpp b/unittests/compiled_tests.cpp index da7eb7c..9a9a4a5 100644 --- a/unittests/compiled_tests.cpp +++ b/unittests/compiled_tests.cpp @@ -2,6 +2,7 @@ // caught in other cpp files if chaiscript causes them #include +#include #ifdef CHAISCRIPT_MSVC #pragma warning(push) @@ -518,6 +519,65 @@ TEST_CASE("Utility_Test utility class wrapper") } +enum Utility_Test_Numbers +{ + ONE, + TWO, + THREE +}; + +void do_something_with_enum_vector(const std::vector &v) +{ + CHECK(v.size() == 3); + CHECK(v[0] == ONE); + CHECK(v[1] == THREE); + CHECK(v[2] == TWO); +} + +TEST_CASE("Utility_Test utility class wrapper for enum") +{ + + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + + using namespace chaiscript; + + chaiscript::utility::add_class(*m, + "Utility_Test_Numbers", + { { ONE, "ONE" }, + { TWO, "TWO" }, + { THREE, "THREE" } + + } + ); + + + chaiscript::ChaiScript chai; + chai.add(m); + + CHECK(chai.eval("ONE ") == 0); + CHECK(chai.eval("TWO ") == 1); + CHECK(chai.eval("THREE ") == 2); + + CHECK(chai.eval("ONE == 0")); + + chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector"); + chai.add(chaiscript::vector_conversion>()); + CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]")); + CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])")); + CHECK_NOTHROW(chai.eval("[ONE]")); + + const auto v = chai.eval>("a"); + CHECK(v.size() == 3); + CHECK(v.at(1) == TWO); + + CHECK(chai.eval("ONE == ONE")); + CHECK(chai.eval("ONE != TWO")); + CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO")); + + +} + + ////// Object copy count test class Object_Copy_Count_Test @@ -802,3 +862,54 @@ TEST_CASE("Test long long dispatch") chai.eval("ulonglong(15)"); } + +struct Returned_Converted_Config +{ + int num_iterations; + int something_else; + std::string a_string; + std::function a_function; +}; + + +TEST_CASE("Return of converted type from script") +{ + chaiscript::ChaiScript chai; + + chai.add(chaiscript::constructor(), "Returned_Converted_Config"); + chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations"); + chai.add(chaiscript::fun(&Returned_Converted_Config::something_else), "something_else"); + chai.add(chaiscript::fun(&Returned_Converted_Config::a_string), "a_string"); + chai.add(chaiscript::fun(&Returned_Converted_Config::a_function), "a_function"); + chai.add(chaiscript::vector_conversion>()); + + auto c = chai.eval>(R"( + var c = Returned_Converted_Config(); + + c.num_iterations = 5; + c.something_else = c.num_iterations * 2; + c.a_string = "string"; + c.a_function = fun(s) { s.size(); } + + print("making vector"); + var v = []; + print("adding config item"); + v.push_back_ref(c); + print("returning vector"); + v; + + )"); + + + std::cout << typeid(decltype(c)).name() << std::endl; + + std::cout << "Info: " << c.size() << " " << &c[0] << std::endl; + + std::cout << "num_iterations " << c[0].num_iterations << '\n' + << "something_else " << c[0].something_else << '\n' + << "a_string " << c[0].a_string << '\n' + << "a_function " << c[0].a_function("bob") << '\n'; + + chai.add(chaiscript::user_type(), "Returned_Converted_Config"); +} +