diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 3e2bc73..aabb2e0 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -12,6 +12,7 @@ #include "register_function.hpp" #include "operators.hpp" #include "boxed_pod_value.hpp" +#include namespace chaiscript { @@ -505,6 +506,32 @@ namespace chaiscript } } + template + static std::vector do_return_boxed_value_vector(const boost::function &f, + const Proxy_Function_Base *b) + { + typedef typename boost::function_types::result_type::type Vector; + Vector v = f(b); + + std::vector vbv; + for (typename Vector::const_iterator itr = v.begin(); + itr != v.end(); + ++itr) + { + vbv.push_back(const_var(*itr)); + } + + return vbv; + } + + template + static boost::function (const Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) + { + typedef typename boost::function_types::result_type::type Vector; + boost::function func(f); + return boost::bind(&do_return_boxed_value_vector, func, _1); + } + public: /** * perform all common bootstrap functions for std::string, void and POD types @@ -518,6 +545,16 @@ namespace chaiscript m->add(user_type(), "function"); m->add(user_type(), "exception"); + m->add(fun(&Proxy_Function_Base::get_arity), "get_arity"); + m->add(fun(&Proxy_Function_Base::annotation), "get_annotation"); + m->add(fun(&Proxy_Function_Base::operator()), "call"); + m->add(fun(&Proxy_Function_Base::operator==), "=="); + + + m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_param_types)), "get_param_types"); + m->add(fun(return_boxed_value_vector(&Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); + + m->add(user_type(), "runtime_error"); m->add(constructor(), "runtime_error"); m->add(fun(boost::function(&what)), "what"); @@ -550,6 +587,9 @@ namespace chaiscript m->add(fun(&Type_Info::name), "cpp_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_equal), "bare_equal"); + typedef bool (Type_Info::*typeinfocompare)(const Type_Info &) const; + m->add(fun(typeinfocompare(&Type_Info::operator==)), "=="); + m->add(fun(&Type_Info::bare_equal), "bare_equal"); basic_constructors("bool", m); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index acc9366..01a4938 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -449,26 +449,27 @@ namespace detail { assignable_type(type, m); input_range_type(type, m); - - m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ - if ( rhs.size() != this.size() ) { \ - return false; \ - } else { \ - var r1 = range(this); \ - var r2 = range(rhs); \ - while (!r1.empty()) \ - { \ - if (!eq(r1.front(), r2.front())) \ + if (typeid(VectorType) == typeid(std::vector)) + { + m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ + if ( rhs.size() != this.size() ) { \ + return false; \ + } else { \ + var r1 = range(this); \ + var r2 = range(rhs); \ + while (!r1.empty()) \ { \ - return false; \ + if (!eq(r1.front(), r2.front())) \ + { \ + return false; \ + } \ + r1.pop_front(); \ + r2.pop_front(); \ } \ - r1.pop_front(); \ - r2.pop_front(); \ - } \ - return true; \ - } \ - }"); - + return true; \ + } \ + }"); + } return m; } diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 786ea13..67eba3e 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -120,22 +120,70 @@ namespace chaiscript { public: Dispatch_Function(const std::vector > &t_funcs) - : Proxy_Function_Base(std::vector()), + : Proxy_Function_Base(build_type_infos(t_funcs)), m_funcs(t_funcs) { } - virtual bool operator==(const Proxy_Function_Base &) const + virtual bool operator==(const Proxy_Function_Base &rhs) const { - return false; + try { + const Dispatch_Function &dispatchfun = dynamic_cast(rhs); + return m_funcs == dispatchfun.m_funcs; + } catch (const std::bad_cast &) { + return false; + } } virtual ~Dispatch_Function() {} + virtual std::vector get_contained_functions() const + { + typedef std::vector > function_vec; + + function_vec::const_iterator begin = m_funcs.begin(); + const function_vec::const_iterator end = m_funcs.end(); + + std::vector fs; + + while (begin != end) + { + fs.push_back(begin->second); + ++begin; + } + + return fs; + } + virtual int get_arity() const { - return -1; + typedef std::vector > function_vec; + + function_vec::const_iterator begin = m_funcs.begin(); + const function_vec::const_iterator end = m_funcs.end(); + + if (begin != end) + { + int arity = begin->second->get_arity(); + + ++begin; + + while (begin != end) + { + if (arity != begin->second->get_arity()) + { + // The arities in the list do not match, so it's unspecified + return -1; + } + + ++begin; + } + + return arity; + } + + return -1; // unknown arity } virtual bool call_match(const std::vector &vals) const @@ -160,7 +208,7 @@ namespace chaiscript virtual std::string annotation() const { - return ""; + return "Multiple method dispatch function wrapper."; } protected: @@ -171,6 +219,54 @@ namespace chaiscript private: std::vector > m_funcs; + + static std::vector build_type_infos(const std::vector > &t_funcs) + { + typedef std::vector > function_vec; + + function_vec::const_iterator begin = t_funcs.begin(); + const function_vec::const_iterator end = t_funcs.end(); + + if (begin != end) + { + std::vector type_infos = begin->second->get_param_types(); + + ++begin; + + bool sizemismatch = false; + + while (begin != end) + { + std::vector param_types = begin->second->get_param_types(); + + if (param_types.size() != type_infos.size()) + { + sizemismatch = true; + } + + for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i) + { + if (!(type_infos[i] == param_types[i])) + { + type_infos[i] = detail::Get_Type_Info::get(); + } + } + + ++begin; + } + + assert(type_infos.size() > 0 && " type_info vector size is < 0, this is only possible if something else is broken"); + + if (sizemismatch) + { + type_infos.resize(1); + } + + return type_infos; + } + + return std::vector(); + } }; @@ -412,6 +508,15 @@ namespace chaiscript { throw std::range_error("Object not known: " + name); } else { + + if (funcs.size() == 1) + { + // Return the first item if there is only one, + // no reason to take the cast of the extra level of dispatch + return const_var(funcs.begin()->second); + } + + Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs))); return f; } diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 18cd649..3a4eaa8 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -90,6 +90,13 @@ namespace chaiscript } } + virtual std::vector get_contained_functions() const + { + std::vector fs; + fs.push_back(m_func); + return fs; + } + virtual int get_arity() const { diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index fbc854d..8baa5b3 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -77,6 +77,11 @@ namespace chaiscript virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool call_match(const std::vector &vals) const = 0; + virtual std::vector > get_contained_functions() const + { + return std::vector >(); + } + //! Return true if the function is a possible match //! to the passed in values @@ -192,9 +197,9 @@ namespace chaiscript { } - virtual bool operator==(const Proxy_Function_Base &) const + virtual bool operator==(const Proxy_Function_Base &rhs) const { - return false; + return this == &rhs; } virtual bool call_match(const std::vector &vals) const @@ -255,6 +260,7 @@ namespace chaiscript { std::vector types; + // For the return type types.push_back(detail::Get_Type_Info::get()); if (arity >= 0) @@ -263,8 +269,6 @@ namespace chaiscript { types.push_back(detail::Get_Type_Info::get()); } - } else { - types.push_back(detail::Get_Type_Info >::get()); } return types; @@ -318,6 +322,14 @@ namespace chaiscript return (*m_f)(build_param_list(params)); } + virtual std::vector get_contained_functions() const + { + std::vector fs; + fs.push_back(m_f); + return fs; + } + + std::vector build_param_list(const std::vector ¶ms) const { typedef std::vector::const_iterator pitr; diff --git a/unittests/dispatch_functions.chai b/unittests/dispatch_functions.chai new file mode 100644 index 0000000..ea7334e --- /dev/null +++ b/unittests/dispatch_functions.chai @@ -0,0 +1,11 @@ +assert_equal(`==`, `==`); +assert_not_equal(`==`, `<`); +assert_equal(`<`.get_arity(), 2); +assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper."); +assert_equal(get_arity.get_contained_functions().size(), 0); +assert_equal(get_arity.get_arity(), 1); +assert_equal(get_arity.get_param_types().size(), 2); + +var paramtypes = get_arity.get_param_types(); + +assert_equal(true, paramtypes[1].bare_equal(function_type)); diff --git a/unittests/function_introspection.chai b/unittests/function_introspection.chai new file mode 100644 index 0000000..fa83955 --- /dev/null +++ b/unittests/function_introspection.chai @@ -0,0 +1,28 @@ + +#Test Function Description +def test_function(a) +{ + return a; +} + +assert_equal(test_function.get_arity(), 1); +assert_equal(test_function.get_annotation(), "#Test Function Description\n"); +assert_equal(test_function.get_contained_functions().size(), 0); +assert_equal(test_function.get_param_types().size(), 2); + +assert_equal(test_function, test_function); + +assert_not_equal(test_function, `+`); + +assert_equal(test_function.call([1]), 1); + +assert_equal(2, `==`.get_arity()); + +// < should be the merging of two functions bool <(PODObject, PODObject) and bool <(string, string) +// we want to peel it apart and make sure that's true +var types = `<`.get_param_types(); +assert_equal(3, types.size()); +assert_equal(true, types[0].bare_equal(bool_type)); +assert_equal(true, types[1].bare_equal(Object_type)); +assert_equal(true, types[2].bare_equal(Object_type)); +assert_equal(2, `<`.get_contained_functions().size()); diff --git a/unittests/unit_test.inc b/unittests/unit_test.inc index e457a01..fbd6633 100644 --- a/unittests/unit_test.inc +++ b/unittests/unit_test.inc @@ -10,6 +10,18 @@ def assert_equal(x, y) } } +def assert_not_equal(x, y) +{ + if (!(x == y)) + { + // Passes + } else { + // Fails + print("assert_not_equal failure: got " + to_string(y) + " which was not expected."); + exit(-1); + } +} + def assert_throws(desc, x) { if (throws_exception(x))