From bd9af5eff45e7a12e3e2b0f7abd1ba7f1d88ce26 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 14 Aug 2015 21:58:54 -0600 Subject: [PATCH] Order typed functions over untyped specifically the chaiscript defined ones --- .../chaiscript/dispatchkit/dispatchkit.hpp | 226 ++++++++++++------ .../dispatchkit/dynamic_object_detail.hpp | 32 ++- .../dispatchkit/proxy_functions.hpp | 49 +++- unittests/clone_object.chai | 38 +++ 4 files changed, 264 insertions(+), 81 deletions(-) create mode 100644 unittests/clone_object.chai diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 43cb7b1..a7b7eda 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -732,7 +732,6 @@ namespace chaiscript /// \throws std::range_error if it does not Boxed_Value get_function_object(const std::string &t_name) const { -// std::cout << "Getting function object: " << t_name << '\n'; chaiscript::detail::threading::shared_lock l(m_mutex); const auto &funs = get_boxed_functions_int(); @@ -1026,6 +1025,13 @@ namespace chaiscript void dump_function(const std::pair &f) const { std::vector params = f.second->get_param_types(); + std::vector> typed_params; + + auto func(std::dynamic_pointer_cast(f.second)); + if (func) { + typed_params = func->get_dynamic_param_types().types(); + } + std::string annotation = f.second->annotation(); if (annotation.size() > 0) { @@ -1034,19 +1040,20 @@ namespace chaiscript dump_type(params.front()); std::cout << " " << f.first << "("; - for (std::vector::const_iterator itr = params.begin() + 1; - itr != params.end(); - ) + for (size_t i = 1; i < params.size(); ++i) { - dump_type(*itr); - ++itr; + if (!typed_params.empty() && !typed_params[i-1].first.empty()) { + std::cout << typed_params[i-1].first; + } else { + dump_type(params[i]); + } - if (itr != params.end()) - { + if (i != params.size() - 1) { std::cout << ", "; } } + std::cout << ") \n"; } @@ -1253,97 +1260,166 @@ namespace chaiscript return m_state.m_functions; } - static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) + + static std::vector param_types(const Proxy_Function &t_f) { + assert(t_f); + return t_f->get_param_types(); + } - auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); - auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); + static std::vector> param_types(const std::shared_ptr &t_f) + { + assert(t_f); + const auto types = t_f->get_dynamic_param_types().types(); + std::vector> ret(1); + ret.insert(ret.end(), types.begin(), types.end()); + return ret; + } - if (dynamic_lhs && dynamic_rhs) + static Type_Info type_info(const std::pair &t_ti) + { + return t_ti.second; + } + + static Type_Info type_info(const Type_Info &t_ti) + { + return t_ti; + } + + static std::string dynamic_type_name(const std::pair &t_ti) + { + return t_ti.first.empty()?t_ti.second.name():t_ti.first; + } + + static std::string dynamic_type_name(const Type_Info &ti) + { + return ti.name(); + } + + + template + static bool params_less_than(const LHS &t_lhs, const RHS &t_rhs) { - if (dynamic_lhs->get_guard()) - { - return dynamic_rhs->get_guard() ? false : true; - } else { - return false; - } - } + assert(t_lhs); + assert(t_rhs); + const auto lhsparamtypes = param_types(t_lhs); + const auto rhsparamtypes = param_types(t_rhs); - if (dynamic_lhs && !dynamic_rhs) - { - return false; - } - - if (!dynamic_lhs && dynamic_rhs) - { - return true; - } - - const auto &lhsparamtypes = lhs->get_param_types(); - const auto &rhsparamtypes = rhs->get_param_types(); - - const auto lhssize = lhsparamtypes.size(); - const auto rhssize = rhsparamtypes.size(); + const auto lhssize = lhsparamtypes.size(); + const auto rhssize = rhsparamtypes.size(); #ifdef CHAISCRIPT_HAS_MAGIC_STATICS - static auto boxed_type = user_type(); - static auto boxed_pod_type = user_type(); + static auto boxed_type = user_type(); + static auto boxed_pod_type = user_type(); + static auto dynamic_type = user_type(); #else - auto boxed_type = user_type(); - auto boxed_pod_type = user_type(); + auto boxed_type = user_type(); + auto boxed_pod_type = user_type(); + auto dynamic_type = user_type(); #endif - for (size_t i = 1; i < lhssize && i < rhssize; ++i) - { - const Type_Info < = lhsparamtypes[i]; - const Type_Info &rt = rhsparamtypes[i]; - - if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) + for (size_t i = 1; i < lhssize && i < rhssize; ++i) { - continue; // The first two types are essentially the same, next iteration - } + const Type_Info lt = type_info(lhsparamtypes[i]); + const Type_Info rt = type_info(rhsparamtypes[i]); + const std::string ln = dynamic_type_name(lhsparamtypes[i]); + const std::string rn = dynamic_type_name(rhsparamtypes[i]); - // const is after non-const for the same type - if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) - { - return false; - } + if ( (lt.bare_equal(dynamic_type) || lt.is_undef()) + && (rt.bare_equal(dynamic_type) || rt.is_undef())) + { - if (lt.bare_equal(rt) && !lt.is_const()) - { - return true; - } + if (!ln.empty() && rn.empty()) { + return true; + } else if (ln.empty() && !rn.empty()) { + return false; + } else if (!ln.empty() && !rn.empty()) { + if (ln < rn) { + return true; + } else if (rn < ln) { + return false; + } - // boxed_values are sorted last - if (lt.bare_equal(boxed_type)) - { - return false; - } + // the remaining cases are handled by the is_const rules below + } + } - if (rt.bare_equal(boxed_type)) - { - if (lt.bare_equal(boxed_pod_type)) + if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) + { + continue; // The first two types are essentially the same, next iteration + } + + // const is after non-const for the same type + if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) + { + return false; + } + + if (lt.bare_equal(rt) && !lt.is_const()) { return true; } - return true; + + // boxed_values are sorted last + if (lt.bare_equal(boxed_type)) + { + return false; + } + + if (rt.bare_equal(boxed_type)) + { + if (lt.bare_equal(boxed_pod_type)) + { + return true; + } + return true; + } + + if (lt.bare_equal(boxed_pod_type)) + { + return false; + } + + if (rt.bare_equal(boxed_pod_type)) + { + return true; + } + + // otherwise, we want to sort by typeid + return lt < rt; } - if (lt.bare_equal(boxed_pod_type)) - { - return false; + // if everything else checks out, sort on guard + // + auto dynamic_lhs(std::dynamic_pointer_cast(t_lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(t_rhs)); + + if (dynamic_lhs && dynamic_rhs) { + if (dynamic_lhs->get_guard() && !dynamic_rhs->get_guard()) { + return true; + } else if (dynamic_rhs->get_guard()) { + return false; + } } - if (rt.bare_equal(boxed_pod_type)) - { - return true; - } - - // otherwise, we want to sort by typeid - return lt < rt; + return false; } - return false; + static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) + { + auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); + + if (dynamic_lhs && dynamic_rhs) + { + return params_less_than(dynamic_lhs, dynamic_rhs); + } else if (dynamic_lhs) { + return params_less_than(dynamic_lhs, rhs); + } else if (dynamic_rhs) { + return params_less_than(lhs, dynamic_rhs); + } else { + return params_less_than(lhs, rhs); + } } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 9d501ae..710c927 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -39,7 +39,8 @@ namespace chaiscript /// A Proxy_Function implementation designed for calling a function /// that is automatically guarded based on the first param based on the /// param's type name - class Dynamic_Object_Function : public Proxy_Function_Base + class Dynamic_Object_Function : public Proxy_Function_Base, public Dynamic_Function_Interface + { public: Dynamic_Object_Function( @@ -72,6 +73,17 @@ namespace chaiscript Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function(Dynamic_Object_Function &) = delete; + virtual Param_Types get_dynamic_param_types() const { + auto dynamic(std::dynamic_pointer_cast(m_func)); + + if (dynamic) { + return dynamic->get_dynamic_param_types(); + } else { + return Param_Types(get_param_types()); + } + } + + virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE { if (const auto *df = dynamic_cast(&f)) @@ -182,7 +194,7 @@ namespace chaiscript * that is automatically guarded based on the first param based on the * param's type name */ - class Dynamic_Object_Constructor : public Proxy_Function_Base + class Dynamic_Object_Constructor : public Proxy_Function_Base, public Dynamic_Function_Interface { public: Dynamic_Object_Constructor( @@ -191,6 +203,7 @@ namespace chaiscript : 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 ); assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); } @@ -210,6 +223,17 @@ namespace chaiscript virtual ~Dynamic_Object_Constructor() {} + virtual Param_Types get_dynamic_param_types() const { + auto dynamic(std::dynamic_pointer_cast(m_func)); + + if (dynamic) { + return dynamic->get_dynamic_param_types(); + } else { + return Param_Types(get_param_types()); + } + } + + virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE { const Dynamic_Object_Constructor *dc = dynamic_cast(&f); @@ -222,7 +246,7 @@ namespace chaiscript new_vals.insert(new_vals.end(), vals.begin(), vals.end()); return m_func->call_match(new_vals, t_conversions); - } + } virtual std::string annotation() const CHAISCRIPT_OVERRIDE { @@ -232,7 +256,7 @@ namespace chaiscript protected: 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)); + auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); std::vector new_params{bv}; new_params.insert(new_params.end(), params.begin(), params.end()); diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 156831f..940468e 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -53,6 +53,13 @@ namespace chaiscript m_doti(user_type()) {} + Param_Types(const std::vector &t_types) + : m_types(build_param_types(t_types)), + m_has_types(false), + m_doti(user_type()) + { + } + Param_Types(std::vector> t_types) : m_types(std::move(t_types)), m_has_types(false), @@ -61,6 +68,18 @@ namespace chaiscript update_has_types(); } + static std::vector> build_param_types(const std::vector &t_types) + { + std::vector> retval; + std::transform(t_types.begin(), t_types.end(), std::back_inserter(retval), + [](const Type_Info &ti){ + return std::make_pair(std::string(), ti); + } + ); + + return retval; + } + void push_front(std::string t_name, Type_Info t_ti) { m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti)); @@ -295,11 +314,18 @@ namespace chaiscript namespace dispatch { + class Dynamic_Function_Interface + { + public: + virtual ~Dynamic_Function_Interface() {} + virtual Param_Types get_dynamic_param_types() const = 0; + }; + /** * A Proxy_Function implementation that is not type safe, the called function * is expecting a vector that it works with how it chooses. */ - class Dynamic_Proxy_Function : public Proxy_Function_Base + class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface { public: Dynamic_Proxy_Function( @@ -349,6 +375,9 @@ namespace chaiscript return m_description; } + virtual Param_Types get_dynamic_param_types() const { + return m_param_types; + } protected: bool test_guard(const std::vector ¶ms, const Type_Conversions &t_conversions) const @@ -367,6 +396,8 @@ namespace chaiscript } } + + private: static std::vector build_param_type_list(const Param_Types &t_types) { @@ -678,6 +709,8 @@ namespace chaiscript std::reference_wrapper> m_f; std::shared_ptr> m_shared_ptr_holder; }; + + /// Attribute getter Proxy_Function implementation template class Attribute_Access : public Proxy_Function_Base @@ -875,6 +908,15 @@ namespace chaiscript std::vector> ordered_funcs; ordered_funcs.reserve(funcs.size()); +#ifdef CHAISCRIPT_HAS_MAGIC_STATICS + static auto boxed_type = user_type(); + static auto dynamic_type = user_type(); +#else + auto boxed_type = user_type(); + auto dynamic_type = user_type(); +#endif + + for (const auto &func : funcs) { const auto arity = func->get_arity(); @@ -886,7 +928,10 @@ namespace chaiscript size_t numdiffs = 0; for (size_t i = 0; i < plist.size(); ++i) { - if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) + const auto &p_type = plist[i].get_type_info(); + const auto &f_type = func->get_param_types()[i+1]; + + if (!(f_type.bare_equal(boxed_type) && p_type.bare_equal(dynamic_type)) && !f_type.bare_equal(p_type)) { ++numdiffs; } diff --git a/unittests/clone_object.chai b/unittests/clone_object.chai new file mode 100644 index 0000000..78c38a2 --- /dev/null +++ b/unittests/clone_object.chai @@ -0,0 +1,38 @@ +GLOBAL clone_count = 0; + +class Cloneable +{ + def Cloneable() { + } + +} + + +def clone(Cloneable c) +{ + print("Clone called"); + ++clone_count; + return c; +} + + +class MyObject +{ + def MyObject() { + this.data = Cloneable(); + } + + var data; +} + + +assert_equal(0, clone_count); + +var o = MyObject(); + +assert_equal(0, clone_count); + +var p = o; + +assert_equal(1, clone_count); +