diff --git a/cheatsheet.md b/cheatsheet.md index 594b2f7..9ff4ad4 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -80,6 +80,18 @@ It's not strictly necessary to add types, but it helps with many things. Cloning chai.add(chaiscript::user_type, "MyClass"); ``` +## Adding Type Conversions + +User defined type conversions are possible, defined in either script or in C++. + +A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition: + +``` +chai.add(chaiscript::vector_conversion>()); +``` + +This allows you to pass a ChaiScript function to a function requiring `std::vector` + ## Adding Objects ``` diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 6bac83a..09fc617 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -14,8 +14,10 @@ #include #include #else +#ifndef CHAISCRIPT_NO_THREADS_WARNING #pragma message ("ChaiScript is compiling without thread safety.") #endif +#endif #include "chaiscript_defines.hpp" @@ -153,6 +155,7 @@ namespace chaiscript private: + /// \todo this leaks thread instances. It needs to be culled from time to time std::shared_ptr get_tls() const { unique_lock lock(m_mutex); diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 31344d4..c2be40f 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -36,7 +36,7 @@ namespace chaiscript } bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) - : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast") + : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) { } diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index a763e48..1a03888 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -319,7 +319,7 @@ namespace chaiscript /// Add back insertion sequence concept to the given ContainerType /// http://www.sgi.com/tech/stl/BackInsertionSequence.html template - ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared()) + ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared()) { typedef typename ContainerType::reference (ContainerType::*backptr)(); @@ -328,8 +328,16 @@ namespace chaiscript typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &); m->add(fun(static_cast(&ContainerType::push_back)), - []()->std::string{ - if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + [&]()->std::string{ + if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + m->eval( + "# Pushes the second value onto the container while making a clone of the value\n" + "def push_back(" + type + " container, x)\n" + "{ \n" + " container.push_back_ref(clone(x)) \n" + "} \n" + ); + return "push_back_ref"; } else { return "push_back"; @@ -345,7 +353,7 @@ namespace chaiscript /// Front insertion sequence /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html template - ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = std::make_shared()) + ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared()) { typedef typename ContainerType::reference (ContainerType::*front_ptr)(); typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const; @@ -356,8 +364,15 @@ namespace chaiscript m->add(fun(static_cast(&ContainerType::front)), "front"); m->add(fun(static_cast(&ContainerType::push_front)), - []()->std::string{ + [&]()->std::string{ if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + m->eval( + "# Pushes the second value onto the front of container while making a clone of the value\n" + "def push_front(" + type + " container, x)\n" + "{ \n" + " container.push_front_ref(clone(x)) \n" + "} \n" + ); return "push_front_ref"; } else { return "push_front"; diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 106b9d8..1ddaacc 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -79,13 +79,6 @@ namespace chaiscript } -#ifdef CHAISCRIPT_MSVC - //Thank you MSVC, yes we know that a constant value is being used in the if - // statment in THIS VERSION of the template instantiation -#pragma warning(push) -#pragma warning(disable : 4127) -#endif - if (t_conversions && t_conversions->convertable_type()) { try { @@ -108,10 +101,6 @@ namespace chaiscript throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } -#ifdef CHAISCRIPT_MSVC -#pragma warning(pop) -#endif - } } diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index fb6b5fc..4054b59 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -31,9 +31,9 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions *t_conversions) { - return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions)); + return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions); } }; @@ -44,9 +44,9 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions *t_conversions) { - return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as(); + return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as(); } }; @@ -58,9 +58,9 @@ namespace chaiscript struct Function_Caller_Ret { static void call(const std::vector &t_funcs, - const std::vector ¶ms, const Type_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions *t_conversions) { - dispatch::dispatch(t_funcs, params, t_conversions); + dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()); } }; @@ -70,28 +70,49 @@ namespace chaiscript template struct Build_Function_Caller_Helper { - Build_Function_Caller_Helper(std::vector t_funcs, const Type_Conversions &t_conversions) + Build_Function_Caller_Helper(std::vector t_funcs, const Type_Conversions *t_conversions) : m_funcs(std::move(t_funcs)), m_conversions(t_conversions) { } - Ret operator()(Param...param) + template + Ret operator()(P&& ... param) { return Function_Caller_Ret::value && !std::is_same::value>::call(m_funcs, { - (std::is_reference::value&&!(std::is_same::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)... + box

(std::forward

(param))... }, m_conversions ); } + template + static auto box(Q&& q) -> typename std::enable_if::value&&!std::is_same::type>::type>::value, Boxed_Value>::type + { + return Boxed_Value(std::ref(std::forward(q))); + } + + template + static auto box(Q&& q) -> typename std::enable_if::value&&!std::is_same::type>::type>::value, Boxed_Value>::type + { + return Boxed_Value(std::forward(q)); + } + + template + static Boxed_Value box(Boxed_Value bv) + { + return bv; + } + + std::vector m_funcs; - Type_Conversions m_conversions; + const Type_Conversions *m_conversions; }; + /// \todo what happens if t_conversions is deleted out from under us?! template std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions *t_conversions) { @@ -111,7 +132,7 @@ namespace chaiscript } */ - return std::function(Build_Function_Caller_Helper(funcs, t_conversions?*t_conversions:Type_Conversions())); + return std::function(Build_Function_Caller_Helper(funcs, t_conversions)); } } } diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 9071df3..602d4d9 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -337,7 +337,7 @@ namespace chaiscript Type_Conversions(const Type_Conversions &t_other) : m_mutex(), m_conversions(t_other.get_conversions()), - m_convertableTypes(), + m_convertableTypes(t_other.m_convertableTypes), m_num_types(m_conversions.size()), m_thread_cache(this), m_conversion_saves(this) @@ -575,6 +575,24 @@ namespace chaiscript return chaiscript::make_shared>(user_type(), user_type(), func); } + template + Type_Conversion vector_conversion() + { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); + + To vec; + + for (const Boxed_Value &bv : from_vec) { + vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); + } + + return Boxed_Value(std::move(vec)); + }; + + return chaiscript::make_shared>(user_type>(), user_type(), func); + } + } diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index e15e508..62dc081 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -136,9 +136,11 @@ namespace chaiscript static Type_Info get() { - return Type_Info(std::is_const::type>::type>::value, std::is_reference::value, std::is_pointer::value, + return Type_Info(std::is_const::type>::type>::value, + std::is_reference::value, std::is_pointer::value, std::is_void::value, - std::is_arithmetic::value && !std::is_same::type, bool>::value, + (std::is_arithmetic::value || std::is_arithmetic::type>::value) + && !std::is_same::type, bool>::value, &typeid(T), &typeid(typename Bare_Type::type)); } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 4295a32..e3b792f 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -1050,7 +1050,12 @@ namespace chaiscript std::vector vec; if (!children.empty()) { for (const auto &child : children[0]->children) { - vec.push_back(t_ss->call_function("clone", child->eval(t_ss))); + auto obj = child->eval(t_ss); + if (!obj.is_return_value()) { + vec.push_back(t_ss->call_function("clone", obj)); + } else { + vec.push_back(std::move(obj)); + } } } return const_var(std::move(vec)); @@ -1076,8 +1081,12 @@ namespace chaiscript std::map retval; for (const auto &child : children[0]->children) { - Boxed_Value bv = t_ss->call_function("clone", child->children[1]->eval(t_ss)); - retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(bv); + auto obj = child->children[1]->eval(t_ss); + if (!obj.is_return_value()) { + obj = t_ss->call_function("clone", obj); + } + + retval[t_ss->boxed_cast(child->children[0]->eval(t_ss))] = std::move(obj); } return const_var(std::move(retval)); diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index 88835c5..0fe2a5a 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -127,18 +127,6 @@ def even(x) } -# Pushes the second value onto the container first value while making a clone of the value -def push_back(container, x) : call_exists(push_back_ref, container, x) -{ - container.push_back_ref(clone(x)) -} - -# Pushes the second value onto the front of the container first value while making a clone of the value -def push_front(container, x) : call_exists(push_front_ref, container, x) -{ - container.push_front_ref(clone(x)) -} - # Inserts the third value at the position of the second value into the container of the first # while making a clone. def insert_at(container, pos, x) diff --git a/src/stl_extra.cpp b/src/stl_extra.cpp index 6f0c5e4..e391b18 100644 --- a/src/stl_extra.cpp +++ b/src/stl_extra.cpp @@ -23,7 +23,11 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() { - return chaiscript::bootstrap::standard_library::list_type >("List"); + + auto module = chaiscript::bootstrap::standard_library::list_type >("List"); + module->add(chaiscript::bootstrap::standard_library::vector_type >("u16vector")); + module->add(chaiscript::vector_conversion>()); + return module; } #ifdef __llvm__ diff --git a/src/test_module.cpp b/src/test_module.cpp index c5da4c9..ebccf73 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -34,6 +34,11 @@ class TestBaseType int mdarray[2][3][5]; std::function func_member; + void set_string_val(std::string &t_str) + { + t_str = "42"; + } + private: TestBaseType &operator=(const TestBaseType &) = delete; }; @@ -52,6 +57,7 @@ class Type2 return m_bt.val; } + const char *get_str() const { return m_str.c_str(); @@ -171,6 +177,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::fun(&TestBaseType::val), "val"); m->add(chaiscript::fun(&TestBaseType::const_val), "const_val"); m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func"); + m->add(chaiscript::fun(&TestBaseType::set_string_val), "set_string_val"); #ifndef CHAISCRIPT_MSVC_12 // we cannot support these in MSVC_12 because of a bug in the implementation of diff --git a/unittests/non_const_param.chai b/unittests/non_const_param.chai new file mode 100644 index 0000000..fa385db --- /dev/null +++ b/unittests/non_const_param.chai @@ -0,0 +1,8 @@ +load_module("test_module") + +var t2 = TestBaseType(); + +var s = "5"; +t2.set_string_val(s); +assert_equal(s, "42") + diff --git a/unittests/vector_push_back.chai b/unittests/vector_push_back.chai index 82ba4b4..eea34b7 100644 --- a/unittests/vector_push_back.chai +++ b/unittests/vector_push_back.chai @@ -3,3 +3,11 @@ x.push_back(3) assert_equal(3, x.size()) assert_equal(3, x.back()) assert_equal(1, x.front()) + + +load_module("stl_extra") + +auto uint16v = u16vector(); +uint16v.push_back(1u); +assert_equal(1, uint16v.front()); +