From 43d6f0cf164fac76549c9f79105da02de693152d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 28 Oct 2014 12:43:30 -0600 Subject: [PATCH 01/15] Rename dynamic_cast into type_conversion Prep work for getting user defined type conversions implemented --- include/chaiscript/dispatchkit/boxed_cast.hpp | 8 +- .../dispatchkit/boxed_cast_helper.hpp | 20 +-- .../chaiscript/dispatchkit/boxed_number.hpp | 4 +- .../chaiscript/dispatchkit/dispatchkit.hpp | 14 +- .../dispatchkit/dynamic_cast_conversion.hpp | 132 +++++++++++------- .../chaiscript/dispatchkit/dynamic_object.hpp | 16 +-- .../chaiscript/dispatchkit/function_call.hpp | 14 +- .../dispatchkit/function_call_detail.hpp | 14 +- .../dispatchkit/proxy_functions.hpp | 46 +++--- .../dispatchkit/proxy_functions_detail.hpp | 18 +-- .../chaiscript/language/chaiscript_engine.hpp | 2 +- 11 files changed, 157 insertions(+), 131 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 31d93865..b33d659c 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -18,7 +18,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace detail { namespace exception { class bad_any_cast; @@ -72,7 +72,7 @@ namespace chaiscript /// assert(i == 5); /// \endcode template - typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr) + typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr) { try { return detail::Cast_Helper::cast(bv, t_conversions); @@ -92,12 +92,12 @@ namespace chaiscript // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl; // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // either way, we are not responsible if it doesn't work - return detail::Cast_Helper::cast(t_conversions->boxed_dynamic_cast(bv), t_conversions); + return detail::Cast_Helper::cast(t_conversions->boxed_type_conversion(bv), t_conversions); } catch (...) { try { // std::cout << "trying a down conversion " << typeid(Type).name() << std::endl; // try going the other way - down the inheritance graph - return detail::Cast_Helper::cast(t_conversions->boxed_dynamic_down_cast(bv), t_conversions); + return detail::Cast_Helper::cast(t_conversions->boxed_type_down_conversion(bv), t_conversions); } catch (const chaiscript::detail::exception::bad_any_cast &) { throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 8ae75526..3222fd19 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -17,7 +17,7 @@ namespace chaiscript { - class Dynamic_Cast_Conversions; + class Type_Conversions; namespace detail { @@ -36,7 +36,7 @@ namespace chaiscript { typedef typename std::reference_wrapper::type > Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.get_type_info().bare_equal_type_info(typeid(Result))) { @@ -63,7 +63,7 @@ namespace chaiscript struct Cast_Helper_Inner { typedef const Result * Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.is_ref()) { @@ -89,7 +89,7 @@ namespace chaiscript struct Cast_Helper_Inner { typedef Result * Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (ob.is_ref()) { @@ -107,7 +107,7 @@ namespace chaiscript { typedef Result& Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result))) { @@ -124,7 +124,7 @@ namespace chaiscript { typedef typename std::shared_ptr Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return ob.get().cast >(); } @@ -136,7 +136,7 @@ namespace chaiscript { typedef typename std::shared_ptr Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { if (!ob.get_type_info().is_const()) { @@ -178,7 +178,7 @@ namespace chaiscript { typedef const Boxed_Value & Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return ob; } @@ -190,7 +190,7 @@ namespace chaiscript { typedef Boxed_Value& Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return const_cast(ob); } @@ -246,7 +246,7 @@ namespace chaiscript { typedef typename Cast_Helper_Inner::Result_Type Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { return Cast_Helper_Inner::cast(ob, t_conversions); } diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index f54cd13a..557a20a7 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -19,7 +19,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; } // namespace chaiscript namespace chaiscript @@ -832,7 +832,7 @@ namespace chaiscript { typedef Boxed_Number Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *) { return Boxed_Number(ob); } diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b49d14cc..b8d4e197 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -141,7 +141,7 @@ namespace chaiscript return *this; } - Module &add(Dynamic_Cast_Conversion d) + Module &add(Type_Conversion d) { m_conversions.push_back(std::move(d)); return *this; @@ -197,7 +197,7 @@ namespace chaiscript std::vector > m_funcs; std::vector > m_globals; std::vector m_evals; - std::vector m_conversions; + std::vector m_conversions; template static void apply(InItr begin, const InItr end, T &t) @@ -300,7 +300,7 @@ namespace chaiscript return arity; } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return std::any_of(m_funcs.cbegin(), m_funcs.cend(), [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); @@ -312,7 +312,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return dispatch::dispatch(m_funcs.cbegin(), m_funcs.cend(), params, t_conversions); } @@ -409,7 +409,7 @@ namespace chaiscript } /// Add a new conversion for upcasting to a base class - void add(const Dynamic_Cast_Conversion &d) + void add(const Type_Conversion &d) { m_conversions.add_conversion(d); } @@ -768,7 +768,7 @@ namespace chaiscript m_state.m_reserved_words.insert(name); } - const Dynamic_Cast_Conversions &conversions() const + const Type_Conversions &conversions() const { return m_conversions; } @@ -1138,7 +1138,7 @@ namespace chaiscript int call_depth; }; - Dynamic_Cast_Conversions m_conversions; + Type_Conversions m_conversions; chaiscript::detail::threading::Thread_Storage m_stack_holder; diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 184246ef..9a90e7c5 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -47,34 +47,60 @@ namespace chaiscript }; } - namespace detail + namespace exception { - class Dynamic_Conversion + class bad_boxed_type_cast : public bad_boxed_cast { public: - virtual Boxed_Value convert(const Boxed_Value &derived) const = 0; - virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0; - - const Type_Info &base() const + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, + const std::string &t_what) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to, t_what) { - return m_base; } - const Type_Info &derived() const + + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to) { - return m_derived; + } + + bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(w) + { + } + + virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {} + }; + } + + + namespace detail + { + class Type_Conversion_Base + { + public: + virtual Boxed_Value convert(const Boxed_Value &from) const = 0; + virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; + + const Type_Info &to() const + { + return m_to; + } + const Type_Info &from() const + { + return m_from; } protected: - Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived) - : m_base(t_base), m_derived(t_derived) + Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) + : m_to(t_to), m_from(t_from) { } - virtual ~Dynamic_Conversion() {} + virtual ~Type_Conversion_Base() {} private: - Type_Info m_base; - Type_Info m_derived; + Type_Info m_to; + Type_Info m_from; }; @@ -130,11 +156,11 @@ namespace chaiscript }; template - class Dynamic_Conversion_Impl : public Dynamic_Conversion + class Dynamic_Conversion_Impl : public Type_Conversion_Base { public: Dynamic_Conversion_Impl() - : Dynamic_Conversion(user_type(), user_type()) + : Type_Conversion_Base(user_type(), user_type()) { } @@ -150,94 +176,94 @@ namespace chaiscript }; } - class Dynamic_Cast_Conversions + class Type_Conversions { public: - Dynamic_Cast_Conversions() + Type_Conversions() { } - Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other) + Type_Conversions(const Type_Conversions &t_other) : m_conversions(t_other.get_conversions()) { } - void add_conversion(const std::shared_ptr &conversion) + void add_conversion(const std::shared_ptr &conversion) { chaiscript::detail::threading::unique_lock l(m_mutex); m_conversions.insert(conversion); } - template - bool dynamic_cast_converts() const + template + bool converts() const { - return dynamic_cast_converts(user_type(), user_type()); + return converts(user_type(), user_type()); } - bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const + bool converts(const Type_Info &to, const Type_Info &from) const { - return has_conversion(base, derived) || has_conversion(derived, base); + return has_conversion(to, from) || has_conversion(from, to); } - template - Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const + template + Boxed_Value boxed_type_conversion(const Boxed_Value &from) const { try { - return get_conversion(user_type(), derived.get_type_info())->convert(derived); + return get_conversion(user_type(), from.get_type_info())->convert(from); } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion"); } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation"); } } - template - Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const + template + Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const { try { - return get_conversion(base.get_type_info(), user_type())->convert_down(base); + return get_conversion(to.get_type_info(), user_type())->convert_down(to); } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion"); + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation"); + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation"); } } - bool has_conversion(const Type_Info &base, const Type_Info &derived) const + bool has_conversion(const Type_Info &to, const Type_Info &from) const { chaiscript::detail::threading::shared_lock l(m_mutex); - return find(base, derived) != m_conversions.end(); + return find(to, from) != m_conversions.end(); } - std::shared_ptr get_conversion(const Type_Info &base, const Type_Info &derived) const + std::shared_ptr get_conversion(const Type_Info &to, const Type_Info &from) const { chaiscript::detail::threading::shared_lock l(m_mutex); auto itr = - find(base, derived); + find(to, from); if (itr != m_conversions.end()) { return *itr; } else { - throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name()); + throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name()); } } private: - std::set >::const_iterator find( - const Type_Info &base, const Type_Info &derived) const + std::set >::const_iterator find( + const Type_Info &to, const Type_Info &from) const { return std::find_if(m_conversions.begin(), m_conversions.end(), - [&base, &derived](const std::shared_ptr &conversion) + [&to, &from](const std::shared_ptr &conversion) { - return conversion->base().bare_equal(base) && conversion->derived().bare_equal(derived); + return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); } ); } - std::set > get_conversions() const + std::set> get_conversions() const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -245,19 +271,19 @@ namespace chaiscript } mutable chaiscript::detail::threading::shared_mutex m_mutex; - std::set > m_conversions; + std::set> m_conversions; }; - typedef std::shared_ptr Dynamic_Cast_Conversion; + typedef std::shared_ptr Type_Conversion; - /// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you + /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you /// want automatic conversions up your inheritance hierarchy. /// - /// Create a new base class registration for applying to a module or to the ChaiScript engine + /// Create a new to class registration for applying to a module or to the ChaiScript engine /// Currently, due to limitations in module loading on Windows, and for the sake of portability, /// if you have a type that is introduced in a loadable module and is used by multiple modules /// (through a tertiary dll that is shared between the modules, static linking the new type - /// into both loadable modules would not be portable), you need to register the base type + /// into both loadable modules would not be portable), you need to register the to type /// relationship in all modules that use the newly added type in a polymorphic way. /// /// Example: @@ -268,11 +294,11 @@ namespace chaiscript /// {}; /// /// chaiscript::ChaiScript chai; - /// chai.add(chaiscript::base_class()); + /// chai.add(chaiscript::to_class()); /// \endcode /// template - Dynamic_Cast_Conversion base_class() + Type_Conversion base_class() { //Can only be used with related polymorphic types //may be expanded some day to support conversions other than child -> parent @@ -280,7 +306,7 @@ namespace chaiscript static_assert(std::is_polymorphic::value, "Base class must be polymorphic"); static_assert(std::is_polymorphic::value, "Derived class must be polymorphic"); - return std::shared_ptr(new detail::Dynamic_Conversion_Impl()); + return std::shared_ptr(new detail::Dynamic_Conversion_Impl()); } } diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 5c932408..93ffd269 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -23,7 +23,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace dispatch { class Proxy_Function_Base; } // namespace dispatch @@ -106,7 +106,7 @@ namespace chaiscript } } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { @@ -134,7 +134,7 @@ namespace chaiscript protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) { @@ -144,7 +144,7 @@ namespace chaiscript } } - virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); } @@ -162,7 +162,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const std::unique_ptr &ti, const Dynamic_Cast_Conversions &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions &t_conversions) const { if (bv.get_type_info().bare_equal(m_doti)) { @@ -184,7 +184,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, - const std::unique_ptr &ti, const Dynamic_Cast_Conversions &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions &t_conversions) const { if (bvs.size() > 0) { @@ -248,7 +248,7 @@ namespace chaiscript } } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { std::vector new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; new_vals.insert(new_vals.end(), vals.begin(), vals.end()); @@ -269,7 +269,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { auto bv = var(Dynamic_Object(m_type_name)); std::vector new_params{bv}; diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 66ce0d62..a434f07c 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -18,7 +18,7 @@ namespace chaiscript { class Boxed_Value; -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace detail { template struct Cast_Helper; } // namespace detail @@ -36,7 +36,7 @@ namespace chaiscript /// \param[in] funcs the set of functions to dispatch on. template std::function - functor(const std::vector &funcs, const Dynamic_Cast_Conversions *t_conversions) + functor(const std::vector &funcs, const Type_Conversions *t_conversions) { FunctionType *p=nullptr; return detail::build_function_caller_helper(p, funcs, t_conversions); @@ -55,7 +55,7 @@ namespace chaiscript /// \param[in] func A function to execute. template std::function - functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions) + functor(Const_Proxy_Function func, const Type_Conversions *t_conversions) { return functor(std::vector({func}), t_conversions); } @@ -64,7 +64,7 @@ namespace chaiscript /// and creating a typesafe C++ function caller from it. template std::function - functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions) + functor(const Boxed_Value &bv, const Type_Conversions *t_conversions) { return functor(boxed_cast(bv, t_conversions), t_conversions); } @@ -77,7 +77,7 @@ namespace chaiscript { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { @@ -94,7 +94,7 @@ namespace chaiscript { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { @@ -111,7 +111,7 @@ namespace chaiscript { typedef std::function Result_Type; - static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) + static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index f3c012bc..2da9b7b6 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -32,7 +32,7 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { return boxed_cast(dispatch::dispatch(t_funcs, params, t_conversions)); } @@ -45,7 +45,7 @@ namespace chaiscript struct Function_Caller_Ret { static Ret call(const std::vector &t_funcs, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as(); } @@ -59,7 +59,7 @@ namespace chaiscript struct Function_Caller_Ret { static void call(const std::vector &t_funcs, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { dispatch::dispatch(t_funcs, params, t_conversions); } @@ -71,7 +71,7 @@ namespace chaiscript template struct Build_Function_Caller_Helper { - Build_Function_Caller_Helper(std::vector t_funcs, const Dynamic_Cast_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) { @@ -88,13 +88,13 @@ namespace chaiscript } std::vector m_funcs; - Dynamic_Cast_Conversions m_conversions; + Type_Conversions m_conversions; }; template - std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Dynamic_Cast_Conversions *t_conversions) + std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions *t_conversions) { if (funcs.size() == 1) { @@ -110,7 +110,7 @@ namespace chaiscript // we cannot make any other guesses or assumptions really, so continuing } - return std::function(Build_Function_Caller_Helper(funcs, t_conversions?*t_conversions:Dynamic_Cast_Conversions())); + return std::function(Build_Function_Caller_Helper(funcs, t_conversions?*t_conversions:Type_Conversions())); } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 16ceaf8e..a0cd4b87 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -26,7 +26,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace exception { class bad_boxed_cast; struct arity_error; @@ -55,7 +55,7 @@ namespace chaiscript public: virtual ~Proxy_Function_Base() {} - Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const + Boxed_Value operator()(const std::vector ¶ms, const chaiscript::Type_Conversions &t_conversions) const { Boxed_Value bv = do_call(params, t_conversions); return bv; @@ -68,7 +68,7 @@ namespace chaiscript const std::vector &get_param_types() const { return m_types; } virtual bool operator==(const Proxy_Function_Base &) const = 0; - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; bool has_arithmetic_param() const { @@ -82,7 +82,7 @@ namespace chaiscript //! Return true if the function is a possible match //! to the passed in values - bool filter(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const + bool filter(const std::vector &vals, const Type_Conversions &t_conversions) const { int arity = get_arity(); @@ -106,7 +106,7 @@ namespace chaiscript virtual std::string annotation() const = 0; - static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) + static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions) { if (ti.is_undef() || ti.bare_equal(user_type()) @@ -114,7 +114,7 @@ namespace chaiscript && (ti.bare_equal(user_type()) || ti.bare_equal(bv.get_type_info()) || bv.get_type_info().bare_equal(user_type >()) - || t_conversions.dynamic_cast_converts(ti, bv.get_type_info()) + || t_conversions.converts(ti, bv.get_type_info()) ) ) ) @@ -125,7 +125,7 @@ namespace chaiscript } } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const = 0; + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const = 0; Proxy_Function_Base(std::vector t_types) : m_types(std::move(t_types)), m_has_arithmetic_param(false) @@ -141,7 +141,7 @@ namespace chaiscript } - virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const { const std::vector &types = get_param_types(); @@ -233,7 +233,7 @@ namespace chaiscript && !this->m_guard && !prhs->m_guard); } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return (m_arity < 0 || vals.size() == size_t(m_arity)) && test_guard(vals, t_conversions); @@ -260,7 +260,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (m_arity < 0 || params.size() == size_t(m_arity)) { @@ -278,7 +278,7 @@ namespace chaiscript } private: - bool test_guard(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const + bool test_guard(const std::vector ¶ms, const Type_Conversions &t_conversions) const { if (m_guard) { @@ -351,7 +351,7 @@ namespace chaiscript virtual ~Bound_Function() {} - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return m_f->call_match(build_param_list(vals), t_conversions); } @@ -429,7 +429,7 @@ namespace chaiscript return retval; } - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return (*m_f)(build_param_list(params), t_conversions); } @@ -460,7 +460,7 @@ namespace chaiscript return ""; } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (int(vals.size()) != get_arity()) { @@ -470,7 +470,7 @@ namespace chaiscript return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions); } - virtual bool compare_types_with_cast(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const = 0; }; /** @@ -490,7 +490,7 @@ namespace chaiscript virtual ~Proxy_Function_Impl() {} - virtual bool compare_types_with_cast(const std::vector &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { return detail::compare_types_cast(m_dummy_func, vals, t_conversions); } @@ -506,7 +506,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const { return detail::Do_Call::result_type>::go(m_f, params, t_conversions); } @@ -549,7 +549,7 @@ namespace chaiscript return 1; } - virtual bool call_match(const std::vector &vals, const Dynamic_Cast_Conversions &) const CHAISCRIPT_OVERRIDE + virtual bool call_match(const std::vector &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE { if (vals.size() != 1) { @@ -565,7 +565,7 @@ namespace chaiscript } protected: - virtual Boxed_Value do_call(const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { if (params.size() == 1) { @@ -622,7 +622,7 @@ namespace chaiscript { template bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector &plist, - const Dynamic_Cast_Conversions &t_conversions) + const Type_Conversions &t_conversions) { if (t_func->get_arity() != static_cast(plist.size())) { @@ -650,7 +650,7 @@ namespace chaiscript template Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector &plist, - const Dynamic_Cast_Conversions &t_conversions) + const Type_Conversions &t_conversions) { InItr orig(begin); @@ -714,7 +714,7 @@ namespace chaiscript */ template Boxed_Value dispatch(InItr begin, const InItr &end, - const std::vector &plist, const Dynamic_Cast_Conversions &t_conversions) + const std::vector &plist, const Type_Conversions &t_conversions) { InItr orig(begin); while (begin != end) @@ -745,7 +745,7 @@ namespace chaiscript */ template Boxed_Value dispatch(const Funcs &funcs, - const std::vector &plist, const Dynamic_Cast_Conversions &t_conversions) + const std::vector &plist, const Type_Conversions &t_conversions) { return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions); } diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index b908d1fe..744d40b4 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -20,7 +20,7 @@ #include "type_info.hpp" namespace chaiscript { -class Dynamic_Cast_Conversions; +class Type_Conversions; namespace exception { class bad_boxed_cast; } // namespace exception @@ -72,7 +72,7 @@ namespace chaiscript template struct Try_Cast { - static void do_try(const std::vector ¶ms, int generation, const Dynamic_Cast_Conversions &t_conversions) + static void do_try(const std::vector ¶ms, int generation, const Type_Conversions &t_conversions) { boxed_cast(params[generation], &t_conversions); Try_Cast::do_try(params, generation+1, t_conversions); @@ -83,7 +83,7 @@ namespace chaiscript template<> struct Try_Cast<> { - static void do_try(const std::vector &, int, const Dynamic_Cast_Conversions &) + static void do_try(const std::vector &, int, const Type_Conversions &) { } }; @@ -96,7 +96,7 @@ namespace chaiscript */ template bool compare_types_cast(Ret (*)(Params...), - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { try { Try_Cast::do_try(params, 0, t_conversions); @@ -113,7 +113,7 @@ namespace chaiscript template static Ret do_call(const std::function &f, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) + const std::vector ¶ms, const Type_Conversions &t_conversions, InnerParams &&... innerparams) { return Call_Func::do_call(f, params, t_conversions, std::forward(innerparams)..., params[sizeof...(Params) - count]); } @@ -128,7 +128,7 @@ namespace chaiscript #endif template static Ret do_call(const std::function &f, - const std::vector &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) + const std::vector &, const Type_Conversions &t_conversions, InnerParams &&... innerparams) { return f(boxed_cast(std::forward(innerparams), &t_conversions)...); } @@ -145,7 +145,7 @@ namespace chaiscript */ template Ret call_func(const std::function &f, - const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + const std::vector ¶ms, const Type_Conversions &t_conversions) { if (params.size() == sizeof...(Params)) { @@ -171,7 +171,7 @@ namespace chaiscript struct Do_Call { template - static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) { return Handle_Return::handle(call_func(fun, params, t_conversions)); } @@ -181,7 +181,7 @@ namespace chaiscript struct Do_Call { template - static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) + static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Type_Conversions &t_conversions) { call_func(fun, params, t_conversions); return Handle_Return::handle(); diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 539157c8..b476d297 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -679,7 +679,7 @@ namespace chaiscript /// chaiscript::ChaiScript chai; /// chai.add(chaiscript::base_class()); /// \endcode - ChaiScript &add(const Dynamic_Cast_Conversion &d) + ChaiScript &add(const Type_Conversion &d) { m_engine.add(d); return *this; From 7b42d5307a08f230f53a8524ea4f29cc3a9f6734 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 28 Oct 2014 14:52:24 -0600 Subject: [PATCH 02/15] Add ability to register a user defined type conversion Currently this adds a fair bit of overhead. It will need to be evaluated further before it's merged. --- CMakeLists.txt | 2 +- include/chaiscript/dispatchkit/bootstrap.hpp | 2 +- include/chaiscript/dispatchkit/boxed_cast.hpp | 4 +- .../chaiscript/dispatchkit/dispatchkit.hpp | 2 +- .../dispatchkit/function_call_detail.hpp | 2 +- ...st_conversion.hpp => type_conversions.hpp} | 43 ++++++++++++++++--- .../chaiscript/language/chaiscript_engine.hpp | 9 +++- unittests/user_defined_conversions.chai | 11 +++++ 8 files changed, 62 insertions(+), 13 deletions(-) rename include/chaiscript/dispatchkit/{dynamic_cast_conversion.hpp => type_conversions.hpp} (89%) create mode 100644 unittests/user_defined_conversions.chai diff --git a/CMakeLists.txt b/CMakeLists.txt index c8ef4b9a..720cb73b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,7 +154,7 @@ endif() include_directories(include) -set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) +set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index c4fd18a5..98648da1 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -24,7 +24,7 @@ #include "boxed_number.hpp" #include "boxed_value.hpp" #include "dispatchkit.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "dynamic_object.hpp" #include "operators.hpp" #include "proxy_constructors.hpp" diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index b33d659c..f2074d9d 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -14,7 +14,7 @@ #include "bad_boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "type_info.hpp" namespace chaiscript { @@ -86,7 +86,7 @@ namespace chaiscript #pragma warning(disable : 4127) #endif - if (std::is_polymorphic::type>::value && t_conversions) + if ( /*std::is_polymorphic::type>::value && */ t_conversions) { try { // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl; diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b8d4e197..910987e8 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -27,7 +27,7 @@ #include "boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "dynamic_object.hpp" #include "proxy_constructors.hpp" #include "proxy_functions.hpp" diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 2da9b7b6..ee1d1bd6 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -17,7 +17,7 @@ #include "boxed_cast.hpp" #include "boxed_number.hpp" #include "boxed_value.hpp" -#include "dynamic_cast_conversion.hpp" +#include "type_conversions.hpp" #include "proxy_functions.hpp" namespace chaiscript diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp similarity index 89% rename from include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp rename to include/chaiscript/dispatchkit/type_conversions.hpp index 9a90e7c5..7036fe57 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -45,10 +45,7 @@ namespace chaiscript virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} }; - } - namespace exception - { class bad_boxed_type_cast : public bad_boxed_cast { public: @@ -174,6 +171,32 @@ namespace chaiscript return Dynamic_Caster::cast(t_derived); } }; + + + class Type_Conversion_Impl : public Type_Conversion_Base + { + public: + Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, std::function t_func) + : Type_Conversion_Base(std::move(t_to), std::move(t_from)), + m_func(std::move(t_func)) + { + } + + virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE + { + throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); + } + + virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE + { + /// \todo better handling of errors from the conversion function + return m_func(t_from); + } + + private: + std::function m_func; + }; + } class Type_Conversions @@ -191,6 +214,7 @@ namespace chaiscript void add_conversion(const std::shared_ptr &conversion) { chaiscript::detail::threading::unique_lock l(m_mutex); + /// \todo error if a conversion already exists m_conversions.insert(conversion); } @@ -240,8 +264,7 @@ namespace chaiscript { chaiscript::detail::threading::shared_lock l(m_mutex); - auto itr = - find(to, from); + auto itr = find(to, from); if (itr != m_conversions.end()) { @@ -283,7 +306,7 @@ namespace chaiscript /// Currently, due to limitations in module loading on Windows, and for the sake of portability, /// if you have a type that is introduced in a loadable module and is used by multiple modules /// (through a tertiary dll that is shared between the modules, static linking the new type - /// into both loadable modules would not be portable), you need to register the to type + /// into both loadable modules would not be portable), you need to register the type /// relationship in all modules that use the newly added type in a polymorphic way. /// /// Example: @@ -309,6 +332,14 @@ namespace chaiscript return std::shared_ptr(new detail::Dynamic_Conversion_Impl()); } + namespace { + Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, + const std::function &t_func) + { + return std::shared_ptr(new detail::Type_Conversion_Impl(t_from, t_to, t_func)); + } + } + } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index b476d297..95c4932f 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -26,7 +26,7 @@ #include "../dispatchkit/boxed_cast_helper.hpp" #include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/dispatchkit.hpp" -#include "../dispatchkit/dynamic_cast_conversion.hpp" +#include "../dispatchkit/type_conversions.hpp" #include "../dispatchkit/proxy_functions.hpp" #include "chaiscript_common.hpp" @@ -353,6 +353,13 @@ namespace chaiscript m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type"); + m_engine.add(fun &)> ( + [=](const Type_Info &t_from, const Type_Info &t_to, const std::function &t_func) { + m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func)); + } + ), "add_type_conversion"); + typedef std::string (ChaiScript::*load_mod_1)(const std::string&); typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); diff --git a/unittests/user_defined_conversions.chai b/unittests/user_defined_conversions.chai new file mode 100644 index 00000000..e73e92a0 --- /dev/null +++ b/unittests/user_defined_conversions.chai @@ -0,0 +1,11 @@ + +add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); }); + +// This looks simple, but it takes the string "string" and using the registered +// conversion above, automatically converts that into a Type_Info object, which then +// allows the Type_Info.name() function to be called + +assert_equal("string".name(), "string"); + + + From e85be6eb3d02aec5e7160ec435f5ec8c697e600b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 28 Oct 2014 20:23:19 -0600 Subject: [PATCH 03/15] Add C++ test for user defined conversion --- .../dispatchkit/type_conversions.hpp | 29 +++++++++++++------ .../chaiscript/language/chaiscript_engine.hpp | 2 +- src/test_module.cpp | 22 ++++++++++++++ unittests/user_defined_conversions_2.chai | 9 ++++++ 4 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 unittests/user_defined_conversions_2.chai diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 7036fe57..3d6da1bc 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -107,7 +107,7 @@ namespace chaiscript public: static Boxed_Value cast(const Boxed_Value &t_from) { - if (t_from.get_type_info().bare_equal(user_type())) + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) { if (t_from.is_pointer()) { @@ -157,7 +157,7 @@ namespace chaiscript { public: Dynamic_Conversion_Impl() - : Type_Conversion_Base(user_type(), user_type()) + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) { } @@ -173,10 +173,11 @@ namespace chaiscript }; + template class Type_Conversion_Impl : public Type_Conversion_Base { public: - Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, std::function t_func) + Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) : Type_Conversion_Base(std::move(t_to), std::move(t_from)), m_func(std::move(t_func)) { @@ -194,7 +195,7 @@ namespace chaiscript } private: - std::function m_func; + Callable m_func; }; } @@ -329,16 +330,26 @@ namespace chaiscript static_assert(std::is_polymorphic::value, "Base class must be polymorphic"); static_assert(std::is_polymorphic::value, "Derived class must be polymorphic"); - return std::shared_ptr(new detail::Dynamic_Conversion_Impl()); + return std::make_shared>(); } - namespace { + template Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, - const std::function &t_func) + const Callable &t_func) { - return std::shared_ptr(new detail::Type_Conversion_Impl(t_from, t_to, t_func)); + return std::make_shared>(t_from, t_to, t_func); + } + + template + Type_Conversion type_conversion(const Callable &t_function) + { + auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value { + // not even attempting to call boxed_cast so that we don't get caught in some call recursion + return chaiscript::Boxed_Value(t_function(detail::Cast_Helper::cast(t_bv, nullptr))); + }; + + return std::make_shared>(user_type(), user_type(), func); } - } } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 95c4932f..b5393c54 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -359,7 +359,7 @@ namespace chaiscript m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func)); } ), "add_type_conversion"); - + typedef std::string (ChaiScript::*load_mod_1)(const std::string&); typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); diff --git a/src/test_module.cpp b/src/test_module.cpp index 7b6ff75c..5dac6f44 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -2,6 +2,8 @@ #include #include + + class TestBaseType { public: @@ -22,6 +24,23 @@ class TestBaseType TestBaseType &operator=(const TestBaseType &); }; +class Type2 +{ + public: + Type2(TestBaseType t_bt) + : m_bt(std::move(t_bt)) + { + } + + int get_val() const + { + return m_bt.val; + } + + private: + TestBaseType m_bt; +}; + enum TestEnum { TestValue1 = 1 @@ -95,6 +114,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::user_type(), "TestBaseType"); m->add(chaiscript::user_type(), "TestDerivedType"); m->add(chaiscript::user_type(), "TestMoreDerivedType"); + m->add(chaiscript::user_type(), "Type2"); m->add(chaiscript::constructor(), "TestBaseType"); // m->add(chaiscript::constructor(), "TestBaseType"); @@ -135,7 +155,9 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::fun(&to_int), "to_int"); m->add(chaiscript::fun(&TestBaseType::constMe), "constMe"); + m->add(chaiscript::type_conversion([](const TestBaseType &t_bt) { return Type2(t_bt); })); + m->add(chaiscript::fun(&Type2::get_val), "get_val"); return m; } diff --git a/unittests/user_defined_conversions_2.chai b/unittests/user_defined_conversions_2.chai new file mode 100644 index 00000000..8a349e15 --- /dev/null +++ b/unittests/user_defined_conversions_2.chai @@ -0,0 +1,9 @@ +load_module("test_module") + +auto t := TestBaseType(); + +// This uses the TestBaseType to Type2 user type +// conversion which was added in the module and then calls +// "get_val()" which exists on the Type2 type +assert_equal(t.get_val(), 10); + From 7c766f87a4b48b8c066e0a0a6f250c6f3aa57f8c Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 28 Oct 2014 22:12:03 -0600 Subject: [PATCH 04/15] Add thread specific cache of type info Reduces the number of locks necessary to check of a user defined type conversion should be scanned for / applied. --- include/chaiscript/dispatchkit/boxed_cast.hpp | 2 +- .../dispatchkit/type_conversions.hpp | 47 ++++++++++++++++++- include/chaiscript/dispatchkit/type_info.hpp | 5 ++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index f2074d9d..1fc57558 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -86,7 +86,7 @@ namespace chaiscript #pragma warning(disable : 4127) #endif - if ( /*std::is_polymorphic::type>::value && */ t_conversions) + if (t_conversions && t_conversions->convertable_type()) { try { // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl; diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 3d6da1bc..574f80c1 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -7,6 +7,7 @@ #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ +#include #include #include #include @@ -203,22 +204,53 @@ namespace chaiscript class Type_Conversions { public: + struct Less_Than + { + bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const + { + return *t_lhs != *t_rhs && t_lhs->before(*t_rhs); + } + }; + Type_Conversions() + : m_num_types(0), + m_thread_cache(this) { } Type_Conversions(const Type_Conversions &t_other) - : m_conversions(t_other.get_conversions()) + : m_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()), + m_thread_cache(this) { } + const std::set &thread_cache() const + { + auto &cache = *m_thread_cache; + if (cache.size() != m_num_types) + { + chaiscript::detail::threading::shared_lock l(m_mutex); + cache = m_convertableTypes; + } + + return cache; + } + void add_conversion(const std::shared_ptr &conversion) { chaiscript::detail::threading::unique_lock l(m_mutex); /// \todo error if a conversion already exists m_conversions.insert(conversion); + m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); + m_num_types = m_convertableTypes.size(); } + template + bool convertable_type() const + { + return thread_cache().count(user_type().bare_type_info()) != 0; + } + template bool converts() const { @@ -227,7 +259,14 @@ namespace chaiscript bool converts(const Type_Info &to, const Type_Info &from) const { - return has_conversion(to, from) || has_conversion(from, to); + const auto &types = thread_cache(); + if (types.count(to.bare_type_info()) != 0 && types.count(to.bare_type_info()) != 0) + { + return has_conversion(to, from) || has_conversion(from, to); + } else { + return false; + } + } template @@ -294,8 +333,12 @@ namespace chaiscript return m_conversions; } + mutable chaiscript::detail::threading::shared_mutex m_mutex; std::set> m_conversions; + std::set m_convertableTypes; + std::atomic_size_t m_num_types; + chaiscript::detail::threading::Thread_Storage> m_thread_cache; }; typedef std::shared_ptr Type_Conversion; diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 3e129e42..2cf64559 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -111,6 +111,11 @@ namespace chaiscript } } + CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const + { + return m_bare_type_info; + } + private: const std::type_info *m_type_info; const std::type_info *m_bare_type_info; From e2cf8a48bec583592e9c5f613b77a914bc7e4881 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 29 Oct 2014 07:07:12 -0600 Subject: [PATCH 05/15] Correct check for which types might have conversions --- include/chaiscript/dispatchkit/type_conversions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 574f80c1..2580fb1e 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -260,7 +260,7 @@ namespace chaiscript bool converts(const Type_Info &to, const Type_Info &from) const { const auto &types = thread_cache(); - if (types.count(to.bare_type_info()) != 0 && types.count(to.bare_type_info()) != 0) + if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) { return has_conversion(to, from) || has_conversion(from, to); } else { From 87cee688a83ffd5e7042facf411446bc217bb85b Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Nov 2014 15:52:02 -0600 Subject: [PATCH 06/15] Fix broken type conversion call implementation - We need to properly order the function so that the one with the least number if type differences is the one that is tried first. --- .../chaiscript/dispatchkit/dispatchkit.hpp | 6 +-- .../dispatchkit/proxy_functions.hpp | 52 ++++++++++++------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 910987e8..9b4548de 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -314,7 +314,7 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return dispatch::dispatch(m_funcs.cbegin(), m_funcs.cend(), params, t_conversions); + return dispatch::dispatch(m_funcs, params, t_conversions); } private: @@ -775,9 +775,7 @@ namespace chaiscript Boxed_Value call_function(const std::string &t_name, const std::vector ¶ms) const { - std::vector functions = get_function(t_name); - - return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions); + return dispatch::dispatch(get_function(t_name), params, m_conversions); } Boxed_Value call_function(const std::string &t_name) const diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index a0cd4b87..df446ad6 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -712,17 +712,42 @@ namespace chaiscript * each function against the set of parameters, in order, until a matching * function is found or throw dispatch_error if no matching function is found */ - template - Boxed_Value dispatch(InItr begin, const InItr &end, + template + Boxed_Value dispatch(const Funcs &funcs, const std::vector &plist, const Type_Conversions &t_conversions) { - InItr orig(begin); - while (begin != end) + + std::multimap ordered_funcs; + + for (const auto &func : funcs) + { + int numdiffs = 0; + const auto arity = func->get_arity(); + + if (arity == -1) + { + numdiffs = plist.size(); + } else if (arity == plist.size()) { + for (size_t i = 0; i < plist.size(); ++i) + { + if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) + { + ++numdiffs; + } + } + } else { + continue; + } + + ordered_funcs.insert(std::make_pair(numdiffs, func.get())); + } + + for (const auto &func : ordered_funcs ) { try { - if ((*begin)->filter(plist, t_conversions)) + if (func.second->filter(plist, t_conversions)) { - return (*(*begin))(plist, t_conversions); + return (*(func.second))(plist, t_conversions); } } catch (const exception::bad_boxed_cast &) { //parameter failed to cast, try again @@ -732,22 +757,9 @@ namespace chaiscript //guard failed to allow the function to execute, //try again } - ++begin; } - return detail::dispatch_with_conversions(orig, end, plist, t_conversions); - } - - /** - * Take a vector of functions and a vector of parameters. Attempt to execute - * each function against the set of parameters, in order, until a matching - * function is found or throw dispatch_error if no matching function is found - */ - template - Boxed_Value dispatch(const Funcs &funcs, - const std::vector &plist, const Type_Conversions &t_conversions) - { - return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions); + return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions); } } } From dd12785b72e550dae9642a0d0834af3d41fd0aa5 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sat, 1 Nov 2014 18:40:42 -0600 Subject: [PATCH 07/15] Reduce virtual calls for get_arity Saves compiled code size and some minor runtime differences --- .../chaiscript/dispatchkit/dispatchkit.hpp | 10 ++-- .../chaiscript/dispatchkit/dynamic_object.hpp | 19 ++----- .../dispatchkit/proxy_functions.hpp | 51 ++++++------------- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 9b4548de..d8a4eed0 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -257,7 +257,7 @@ namespace chaiscript { public: Dispatch_Function(std::vector t_funcs) - : Proxy_Function_Base(build_type_infos(t_funcs)), + : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), m_funcs(std::move(t_funcs)) { } @@ -280,15 +280,15 @@ namespace chaiscript } - virtual int get_arity() const CHAISCRIPT_OVERRIDE + static int calculate_arity(const std::vector &t_funcs) { - if (m_funcs.empty()) { + if (t_funcs.empty()) { return -1; } - const auto arity = m_funcs.front()->get_arity(); + const auto arity = t_funcs.front()->get_arity(); - for (const auto &func : m_funcs) + for (const auto &func : t_funcs) { if (arity != func->get_arity()) { diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 93ffd269..69c24d51 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -73,7 +73,7 @@ namespace chaiscript Dynamic_Object_Function( std::string t_type_name, const Proxy_Function &t_func) - : Proxy_Function_Base(t_func->get_param_types()), + : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()), m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type()) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) @@ -84,7 +84,7 @@ namespace chaiscript std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti) - : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), + : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()), m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type()) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) @@ -121,12 +121,6 @@ namespace chaiscript return {m_func}; } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_func->get_arity(); - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return m_func->annotation(); @@ -215,7 +209,7 @@ namespace chaiscript Dynamic_Object_Constructor( std::string t_type_name, const Proxy_Function &t_func) - : Proxy_Function_Base(build_type_list(t_func->get_param_types())), + : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1), m_type_name(std::move(t_type_name)), m_func(t_func) { assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) @@ -256,13 +250,6 @@ namespace chaiscript return m_func->call_match(new_vals, t_conversions); } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - // "this" is not considered part of the arity - return m_func->get_arity() - 1; - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return m_func->annotation(); diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index df446ad6..0da241ee 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -84,13 +84,11 @@ namespace chaiscript //! to the passed in values bool filter(const std::vector &vals, const Type_Conversions &t_conversions) const { - int arity = get_arity(); - - if (arity < 0) + if (m_arity < 0) { return true; - } else if (size_t(arity) == vals.size()) { - if (arity == 0) + } else if (size_t(m_arity) == vals.size()) { + if (m_arity == 0) { return true; } else { @@ -102,7 +100,10 @@ namespace chaiscript } /// \returns the number of arguments the function takes or -1 if it is variadic - virtual int get_arity() const = 0; + int get_arity() const + { + return m_arity; + } virtual std::string annotation() const = 0; @@ -127,8 +128,8 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const = 0; - Proxy_Function_Base(std::vector t_types) - : m_types(std::move(t_types)), m_has_arithmetic_param(false) + Proxy_Function_Base(std::vector t_types, int t_arity) + : m_types(std::move(t_types)), m_has_arithmetic_param(false), m_arity(t_arity) { for (size_t i = 1; i < m_types.size(); ++i) { @@ -175,7 +176,7 @@ namespace chaiscript std::vector m_types; bool m_has_arithmetic_param; - + int m_arity; }; } @@ -216,7 +217,7 @@ namespace chaiscript AST_NodePtr t_parsenode = AST_NodePtr(), std::string t_description = "", Proxy_Function t_guard = Proxy_Function()) - : Proxy_Function_Base(build_param_type_list(t_arity)), + : Proxy_Function_Base(build_param_type_list(t_arity), t_arity), m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)) { } @@ -239,10 +240,6 @@ namespace chaiscript && test_guard(vals, t_conversions); } - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_arity; - } Proxy_Function get_guard() const { @@ -338,8 +335,8 @@ namespace chaiscript public: Bound_Function(const Const_Proxy_Function &t_f, const std::vector &t_args) - : Proxy_Function_Base(build_param_type_info(t_f, t_args)), - m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast(get_param_types().size())-1) + : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast(build_param_type_info(t_f, t_args).size())-1)), + m_f(t_f), m_args(t_args) { assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); } @@ -395,11 +392,6 @@ namespace chaiscript return args; } - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_arity; - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return "Bound: " + m_f->annotation(); @@ -444,17 +436,12 @@ namespace chaiscript { public: Proxy_Function_Impl_Base(std::vector t_types) - : Proxy_Function_Base(std::move(t_types)) + : Proxy_Function_Base(std::move(t_types), t_types.size() - 1) { } virtual ~Proxy_Function_Impl_Base() {} - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return static_cast(m_types.size()) - 1; - } - virtual std::string annotation() const CHAISCRIPT_OVERRIDE { return ""; @@ -524,8 +511,8 @@ namespace chaiscript { public: Attribute_Access(T Class::* t_attr) - : Proxy_Function_Base(param_types()), - m_attr(t_attr) + : Proxy_Function_Base(param_types(), 1), + m_attr(t_attr) { } @@ -543,12 +530,6 @@ namespace chaiscript } } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return 1; - } - virtual bool call_match(const std::vector &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE { if (vals.size() != 1) From 20c0e6016e99e2a0051ad48ac42cc6cea3af2aba Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 2 Nov 2014 14:08:57 -0700 Subject: [PATCH 08/15] Add type_conversion helper and failing unit test --- include/chaiscript/dispatchkit/type_conversions.hpp | 13 +++++++++++++ src/test_module.cpp | 12 +++++++++++- unittests/user_defined_conversions_2.chai | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 2580fb1e..bc6049a1 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -394,6 +394,19 @@ namespace chaiscript return std::make_shared>(user_type(), user_type(), func); } + template + Type_Conversion type_conversion() + { + static_assert(std::is_convertible::value, "Types are not automatically convertible"); + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + // not even attempting to call boxed_cast so that we don't get caught in some call recursion + auto to = To{detail::Cast_Helper::cast(t_bv, nullptr)}; + return chaiscript::Boxed_Value(std::move(to)); + }; + + return std::make_shared>(user_type(), user_type(), func); + } + } diff --git a/src/test_module.cpp b/src/test_module.cpp index 5dac6f44..90293604 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -28,7 +28,8 @@ class Type2 { public: Type2(TestBaseType t_bt) - : m_bt(std::move(t_bt)) + : m_bt(std::move(t_bt)), + m_str("Hello World") { } @@ -37,8 +38,14 @@ class Type2 return m_bt.val; } + const char *get_str() const + { + return m_str.c_str(); + } + private: TestBaseType m_bt; + std::string m_str; }; enum TestEnum @@ -158,6 +165,9 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::type_conversion([](const TestBaseType &t_bt) { return Type2(t_bt); })); m->add(chaiscript::fun(&Type2::get_val), "get_val"); + m->add(chaiscript::fun(&Type2::get_str), "get_str"); + m->add(chaiscript::type_conversion()); + return m; } diff --git a/unittests/user_defined_conversions_2.chai b/unittests/user_defined_conversions_2.chai index 8a349e15..1226ba1c 100644 --- a/unittests/user_defined_conversions_2.chai +++ b/unittests/user_defined_conversions_2.chai @@ -7,3 +7,4 @@ auto t := TestBaseType(); // "get_val()" which exists on the Type2 type assert_equal(t.get_val(), 10); +assert_equal(t.get_str().size(), 11); From c876a890306c27c1687ca880dcdc77e3dcfef0fb Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 2 Nov 2014 21:37:01 -0700 Subject: [PATCH 09/15] Fix crash during user_defined_conversions_2 Temporaries created during user conversion operations were being dropped before the result of the conversion was able to be used. This fixes that by temporarily storing the result of the conversion inside the current Function_Push_Pop context. --- .../chaiscript/dispatchkit/boxed_value.hpp | 8 ++++ .../chaiscript/dispatchkit/dispatchkit.hpp | 25 +++++++++++ .../chaiscript/dispatchkit/handle_return.hpp | 9 ++++ .../dispatchkit/type_conversions.hpp | 42 ++++++++++++++++--- .../chaiscript/language/chaiscript_common.hpp | 5 +++ src/test_module.cpp | 1 + unittests/user_defined_conversions_2.chai | 21 +++++++++- 7 files changed, 103 insertions(+), 8 deletions(-) diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index b5252814..c73358c5 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -67,6 +67,7 @@ namespace chaiscript Data &operator=(Data &&rhs) = default; #endif + Type_Info m_type_info; chaiscript::detail::Any m_obj; void *m_data_ptr; @@ -122,6 +123,13 @@ namespace chaiscript return get(std::ref(*t)); } + template + static std::shared_ptr get(const T *t) + { + return get(std::cref(*t)); + } + + template static std::shared_ptr get(std::reference_wrapper obj) { diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index d8a4eed0..9d785079 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -915,6 +915,22 @@ namespace chaiscript m_state = t_state; } + void save_function_params(std::initializer_list t_params) + { + Stack_Holder &s = *m_stack_holder; + s.call_params.insert(s.call_params.begin(), std::move(t_params)); + } + + void save_function_params(std::vector &&t_params) + { + Stack_Holder &s = *m_stack_holder; + + for (auto &¶m : t_params) + { + s.call_params.insert(s.call_params.begin(), std::move(param)); + } + } + void save_function_params(const std::vector &t_params) { Stack_Holder &s = *m_stack_holder; @@ -923,7 +939,15 @@ namespace chaiscript void new_function_call() { + Stack_Holder &s = *m_stack_holder; + if (s.call_depth == 0) + { + m_conversions.enable_conversion_saves(true); + } + ++m_stack_holder->call_depth; + + save_function_params(m_conversions.take_saves()); } void pop_function_call() @@ -938,6 +962,7 @@ namespace chaiscript /// \todo Critical: this needs to be smarter, memory can expand quickly /// in tight loops involving function calls s.call_params.clear(); + m_conversions.enable_conversion_saves(false); } } diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index cc24fdf1..8f2ebfec 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -48,6 +48,15 @@ namespace chaiscript } }; + template + struct Handle_Return + { + static Boxed_Value handle(const Ret *p) + { + return Boxed_Value(p); + } + }; + template struct Handle_Return &> { diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index bc6049a1..4f1f84cd 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -214,13 +214,16 @@ namespace chaiscript Type_Conversions() : m_num_types(0), - m_thread_cache(this) + m_thread_cache(this), + m_conversion_saves(this) { } Type_Conversions(const Type_Conversions &t_other) : m_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()), - m_thread_cache(this) + m_thread_cache(this), + m_conversion_saves(this) + { } @@ -273,7 +276,9 @@ namespace chaiscript Boxed_Value boxed_type_conversion(const Boxed_Value &from) const { try { - return get_conversion(user_type(), from.get_type_info())->convert(from); + Boxed_Value ret = get_conversion(user_type(), from.get_type_info())->convert(from); + if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); + return ret; } catch (const std::out_of_range &) { throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion"); } catch (const std::bad_cast &) { @@ -285,7 +290,9 @@ namespace chaiscript Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const { try { - return get_conversion(to.get_type_info(), user_type())->convert_down(to); + Boxed_Value ret = get_conversion(to.get_type_info(), user_type())->convert_down(to); + if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); + return ret; } catch (const std::out_of_range &) { throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); } catch (const std::bad_cast &) { @@ -293,6 +300,17 @@ namespace chaiscript } } + void enable_conversion_saves(bool t_val) + { + m_conversion_saves->enabled = t_val; + } + + std::vector take_saves() + { + std::vector ret; + std::swap(ret, m_conversion_saves->saves); + return ret; + } bool has_conversion(const Type_Info &to, const Type_Info &from) const { @@ -334,11 +352,18 @@ namespace chaiscript } + struct Conversion_Saves + { + bool enabled = false; + std::vector saves; + }; + mutable chaiscript::detail::threading::shared_mutex m_mutex; std::set> m_conversions; std::set m_convertableTypes; std::atomic_size_t m_num_types; chaiscript::detail::threading::Thread_Storage> m_thread_cache; + chaiscript::detail::threading::Thread_Storage m_conversion_saves; }; typedef std::shared_ptr Type_Conversion; @@ -400,8 +425,13 @@ namespace chaiscript static_assert(std::is_convertible::value, "Types are not automatically convertible"); auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { // not even attempting to call boxed_cast so that we don't get caught in some call recursion - auto to = To{detail::Cast_Helper::cast(t_bv, nullptr)}; - return chaiscript::Boxed_Value(std::move(to)); + std::cout << " Type conversion to : " << typeid(To).name() << " from " << typeid(From).name() << std::endl; + auto &&from = detail::Cast_Helper::cast(t_bv, nullptr); + std::cout << "Ptr" << static_cast(from) << std::endl; + std::cout << "Ptr" << from << std::endl; + + To to(from); + return chaiscript::Boxed_Value(to); }; return std::make_shared>(user_type(), user_type(), func); diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 1339f861..d15c2d9e 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -549,6 +549,11 @@ namespace chaiscript m_de.save_function_params(t_params); } + void save_params(std::initializer_list t_params) + { + m_de.save_function_params(std::move(t_params)); + } + private: diff --git a/src/test_module.cpp b/src/test_module.cpp index 90293604..cb95326a 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -167,6 +167,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo m->add(chaiscript::fun(&Type2::get_val), "get_val"); m->add(chaiscript::fun(&Type2::get_str), "get_str"); m->add(chaiscript::type_conversion()); + m->add(chaiscript::constructor(), "Type2"); return m; } diff --git a/unittests/user_defined_conversions_2.chai b/unittests/user_defined_conversions_2.chai index 1226ba1c..fdb601ca 100644 --- a/unittests/user_defined_conversions_2.chai +++ b/unittests/user_defined_conversions_2.chai @@ -5,6 +5,23 @@ auto t := TestBaseType(); // This uses the TestBaseType to Type2 user type // conversion which was added in the module and then calls // "get_val()" which exists on the Type2 type -assert_equal(t.get_val(), 10); +//assert_equal(t.get_val(), 10); +//print("Made it past test 1"); + +var t2 := Type2(t); +var str = string(get_str(t2)); + +assert_equal("Hello World", str); +print("Made it past test 2"); + +assert_equal(11, size(get_str(t2))); +print("Made it past test 3"); + + +assert_equal(11, t2.get_str().size()); +print("Made it past test 4"); + +assert_equal(11, t.get_str().size()); +print("Made it past test 5"); + -assert_equal(t.get_str().size(), 11); From 79c5f719752392dabf753305f97acddde1c00bc3 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 2 Nov 2014 21:47:42 -0700 Subject: [PATCH 10/15] Fix compilation on gcc 4.6 --- include/chaiscript/dispatchkit/type_conversions.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 4f1f84cd..b238b972 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -354,7 +354,11 @@ namespace chaiscript struct Conversion_Saves { - bool enabled = false; + Conversion_Saves() + : enabled(false) + {} + + bool enabled; std::vector saves; }; From 5515d058bb1fd319a04ea3da34c9fe1e21fd8596 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 3 Nov 2014 07:33:53 -0700 Subject: [PATCH 11/15] Fix some warnings for clang / 64bit windows --- include/chaiscript/dispatchkit/proxy_functions.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 0da241ee..cad677c0 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -429,14 +429,13 @@ namespace chaiscript private: Const_Proxy_Function m_f; std::vector m_args; - int m_arity; }; class Proxy_Function_Impl_Base : public Proxy_Function_Base { public: Proxy_Function_Impl_Base(std::vector t_types) - : Proxy_Function_Base(std::move(t_types), t_types.size() - 1) + : Proxy_Function_Base(std::move(t_types), static_cast(t_types.size()) - 1) { } @@ -708,7 +707,7 @@ namespace chaiscript if (arity == -1) { numdiffs = plist.size(); - } else if (arity == plist.size()) { + } else if (arity == static_cast(plist.size())) { for (size_t i = 0; i < plist.size(); ++i) { if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) From 5d5e88197146368842e485ef0e6b69eba82c3cc1 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 3 Nov 2014 08:24:02 -0700 Subject: [PATCH 12/15] Fix arity of functions A value was being accessed after it was moved. --- include/chaiscript/dispatchkit/proxy_functions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index cad677c0..e07a864b 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -434,8 +434,8 @@ namespace chaiscript class Proxy_Function_Impl_Base : public Proxy_Function_Base { public: - Proxy_Function_Impl_Base(std::vector t_types) - : Proxy_Function_Base(std::move(t_types), static_cast(t_types.size()) - 1) + Proxy_Function_Impl_Base(const std::vector &t_types) + : Proxy_Function_Base(t_types, static_cast(t_types.size()) - 1) { } From 3f460fdd20fc30df8eac348886d796f07f46274d Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 3 Nov 2014 18:34:33 -0700 Subject: [PATCH 13/15] Fix 64bit msvc warning --- include/chaiscript/dispatchkit/proxy_functions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index e07a864b..fba9b4ff 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -697,11 +697,11 @@ namespace chaiscript const std::vector &plist, const Type_Conversions &t_conversions) { - std::multimap ordered_funcs; + std::multimap ordered_funcs; for (const auto &func : funcs) { - int numdiffs = 0; + size_t numdiffs = 0; const auto arity = func->get_arity(); if (arity == -1) From 99396ba05cc8784f5ee034507dd28ca93255dac0 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 3 Nov 2014 21:37:25 -0700 Subject: [PATCH 14/15] Add \r skipping code from @jespada --- .../chaiscript/language/chaiscript_parser.hpp | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 29ee4b9e..482d653a 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -266,16 +266,27 @@ namespace chaiscript return false; } + /// Skips ChaiScript whitespace, which means space and tab, but not cr/lf - /// jespada: Modified SkipWS to skip optionally CR ('\n') - bool SkipWS(const bool skip_cr=false) { + /// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n") + bool SkipWS(bool skip_cr=false) { bool retval = false; + while (has_more_input()) { - if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && (*m_input_pos == '\n'))) { - if(*m_input_pos == '\n') { + auto end_line = (*m_input_pos != 0) && ((*m_input_pos == '\n') || (*m_input_pos == '\r' && *(m_input_pos+1) == '\n')); + + if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && end_line)) { + + if(end_line) { m_col = 1; ++m_line; - } else { + + if(*(m_input_pos) == '\r') { + // discards lf + ++m_input_pos; + } + } + else { ++m_col; } ++m_input_pos; @@ -284,14 +295,14 @@ namespace chaiscript } else if (SkipComment()) { retval = true; - } - else { + } else { break; } } return retval; } + /// Reads a floating point value from input, without skipping initial whitespace bool Float_() { if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { From 5daf837037af0ec36d7ebb33d4b3ff1875cda502 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Tue, 4 Nov 2014 09:47:32 -0700 Subject: [PATCH 15/15] Increment version number to 5.5.0 --- CMakeLists.txt | 2 +- include/chaiscript/chaiscript_defines.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 720cb73b..bbf8fa1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_VERSION_MAJOR 5) -set(CPACK_PACKAGE_VERSION_MINOR 4) +set(CPACK_PACKAGE_VERSION_MINOR 5) set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 59e302ee..d4412241 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -45,7 +45,7 @@ namespace chaiscript { static const int version_major = 5; - static const int version_minor = 4; + static const int version_minor = 5; static const int version_patch = 0; }