Merge pull request #233 from vrennert/feature_enum_utility_helper

Added template specialization in chaiscript::utility::add_class<Enum> to register bulk constants.
This commit is contained in:
Jason Turner 2016-01-05 14:03:32 -07:00
commit 21048b9e65
4 changed files with 174 additions and 12 deletions

View File

@ -33,14 +33,14 @@ namespace chaiscript
template<typename Result>
struct Cast_Helper_Inner
{
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
typedef typename std::add_const<Result>::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<const Result *>(p));
return *static_cast<const Result *>(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<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{
};
/// Cast_Helper_Inner for casting to a const * type
template<typename Result>
@ -68,7 +62,7 @@ namespace chaiscript
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr()));
return static_cast<const Result *>(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<Result *>(throw_if_null(ob.get_ptr()));
return static_cast<Result *>(ob.get_ptr());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
{
};
template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
{
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<const Result &>
{
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<const Result *>(p);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}

View File

@ -8,12 +8,14 @@
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#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 Enum, typename ModuleType>
typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants)
{
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
t_module.add([](){
// add some comparison and assignment operators
using namespace chaiscript::bootstrap::operators;
return assign<Enum>(not_equal<Enum>(equal<Enum>()));
}());
t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::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);
}
}
}
}

View File

@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
try {
To ret = chaiscript::boxed_cast<To>(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;

View File

@ -2,6 +2,7 @@
// caught in other cpp files if chaiscript causes them
#include <chaiscript/utility/utility.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#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<Utility_Test_Numbers> &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<Utility_Test_Numbers>(*m,
"Utility_Test_Numbers",
{ { ONE, "ONE" },
{ TWO, "TWO" },
{ THREE, "THREE" }
}
);
chaiscript::ChaiScript chai;
chai.add(m);
CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
CHECK(chai.eval<Utility_Test_Numbers>("TWO ") == 1);
CHECK(chai.eval<Utility_Test_Numbers>("THREE ") == 2);
CHECK(chai.eval<bool>("ONE == 0"));
chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector");
chai.add(chaiscript::vector_conversion<std::vector<Utility_Test_Numbers>>());
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<std::vector<Utility_Test_Numbers>>("a");
CHECK(v.size() == 3);
CHECK(v.at(1) == TWO);
CHECK(chai.eval<bool>("ONE == ONE"));
CHECK(chai.eval<bool>("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<int (const std::string &)> a_function;
};
TEST_CASE("Return of converted type from script")
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "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<std::vector<Returned_Converted_Config>>());
auto c = chai.eval<std::vector<Returned_Converted_Config>>(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>(), "Returned_Converted_Config");
}