diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c1dd93..ba114f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,11 @@ IF(BUILD_TESTING) target_link_libraries(utility_test ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB}) add_test(NAME Utility_Test COMMAND utility_test) + + add_executable(inheritance_test unittests/inheritance_test.cpp) + target_link_libraries(inheritance_test ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB}) + add_test(NAME Inheritance_Test COMMAND inheritance_test) + ENDIF(BUILD_TESTING) install(TARGETS chai stl_extra test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript ) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index b28ff25..c921649 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -21,6 +21,7 @@ #include "boxed_value.hpp" #include "type_info.hpp" +#include "type_conversion.hpp" #include "proxy_functions.hpp" #include "proxy_constructors.hpp" #include "dynamic_object.hpp" @@ -43,6 +44,11 @@ namespace chaiscript return *this; } + Module &add(const Type_Conversion &tc) + { + m_conversions.push_back(tc); + return *this; + } //Add a bit of chaiscript to eval during module implementation Module &eval(const std::string &str) @@ -62,12 +68,14 @@ namespace chaiscript { apply(m_typeinfos.begin(), m_typeinfos.end(), t_engine); apply(m_funcs.begin(), m_funcs.end(), t_engine); + apply_nameless(m_conversions.begin(), m_conversions.end(), t_engine); apply_eval(m_evals.begin(), m_evals.end(), t_eval); } private: std::vector > m_typeinfos; std::vector > m_funcs; + std::vector m_conversions; std::vector m_evals; template @@ -80,6 +88,16 @@ namespace chaiscript } } + template + void apply_nameless(InItr begin, InItr end, T &t) const + { + while (begin != end) + { + t.add(*begin); + ++begin; + } + } + template void apply_eval(InItr begin, InItr end, T &t) const { @@ -202,6 +220,7 @@ namespace chaiscript { std::multimap m_functions; std::map m_global_objects; + std::map, Type_Conversion> m_type_conversions; Type_Name_Map m_types; std::set m_reserved_words; }; @@ -230,6 +249,19 @@ namespace chaiscript return add_function(f, name); } + /** + * Add a new type converter to the system + */ + void add(const Type_Conversion &tc) + { + +#ifndef CHAISCRIPT_NO_THREADS + boost::unique_lock l(m_mutex); +#endif + + m_state.m_type_conversions.insert(std::make_pair(std::make_pair(tc.from(), tc.to()), tc)); + } + /** * Set the value of an object, by name. If the object * is not available in the current scope it is created diff --git a/include/chaiscript/dispatchkit/type_conversion.hpp b/include/chaiscript/dispatchkit/type_conversion.hpp new file mode 100644 index 0000000..35fea9c --- /dev/null +++ b/include/chaiscript/dispatchkit/type_conversion.hpp @@ -0,0 +1,178 @@ +#ifndef __CHAISCRIPT_DISPATCH_TYPE_CONVERSION_HPP__ +#define __CHAISCRIPT_DISPATCH_TYPE_CONVERSION_HPP__ + +#include "boxed_value.hpp" +#include "type_info.hpp" +#include +#include +#include +#include + +namespace chaiscript +{ + namespace detail + { + class Type_Conversion_Impl + { + public: + ~Type_Conversion_Impl() + { } + + virtual Boxed_Value convert(const Boxed_Value &v) const = 0; + + Type_Info from() const + { + return m_from; + } + + Type_Info to() const + { + return m_to; + } + + protected: + Type_Conversion_Impl(const Type_Info &t_from, const Type_Info &t_to) + : m_from(t_from), m_to(t_to) + { + } + + private: + Type_Info m_from; + Type_Info m_to; + + }; + + template + class Dynamic_Cast_Conversion : public Type_Conversion_Impl + { + public: + typedef From From_Type; + typedef To To_Type; + + Dynamic_Cast_Conversion() + : Type_Conversion_Impl(user_type(), user_type()) + { } + + virtual ~Dynamic_Cast_Conversion() + { } + + virtual Boxed_Value convert(const Boxed_Value &v) const + { + if (v.is_pointer()) + { + if (v.is_const()) + { + return const_pointer_convert(v); + } else { + return pointer_convert(v); + } + } else { + if (v.is_const()) + { + return const_reference_convert(v); + } else { + return reference_convert(v); + } + } + } + + private: + Boxed_Value pointer_convert(const Boxed_Value &v) const + { + boost::shared_ptr to = + boost::dynamic_pointer_cast(boxed_cast >(v)); + + if (to) { + return Boxed_Value(to); + } else { + throw bad_boxed_cast(v.get_type_info(), typeid(To_Type)); + } + } + + Boxed_Value const_pointer_convert(const Boxed_Value &v) const + { + boost::shared_ptr::type> to = + boost::dynamic_pointer_cast::type>(boxed_cast::type> >(v)); + + if (to) { + return Boxed_Value(to); + } else { + throw bad_boxed_cast(v.get_type_info(), typeid(To_Type)); + } + } + + Boxed_Value reference_convert(const Boxed_Value &v) const + { + To_Type *to = + dynamic_cast(boxed_cast(v)); + + if (to) { + return Boxed_Value(to); + } else { + throw bad_boxed_cast(v.get_type_info(), typeid(To_Type)); + } + } + + Boxed_Value const_reference_convert(const Boxed_Value &v) const + { + typename boost::add_const::type *to = + dynamic_cast::type *>(boxed_cast::type *>(v)); + + if (to) { + return Boxed_Value(to); + } else { + throw bad_boxed_cast(v.get_type_info(), typeid(To_Type)); + } + } + + }; + } + + + class Type_Conversion + { + public: + Type_Conversion(const boost::shared_ptr t_impl) + : m_impl(t_impl) + { + } + + Boxed_Value convert(const Boxed_Value &v) const + { + return m_impl->convert(v); + } + + Type_Info from() const + { + return m_impl->from(); + } + + Type_Info to() const + { + return m_impl->to(); + } + + private: + boost::shared_ptr m_impl; + + }; + + + template + Type_Conversion dynamic_cast_conversion() + { + typedef typename boost::remove_const< + typename boost::remove_pointer< + typename boost::remove_reference::type>::type>::type Cleaned_From; + + typedef typename boost::remove_const< + typename boost::remove_pointer< + typename boost::remove_reference::type>::type>::type Cleaned_To; + + return Type_Conversion(boost::shared_ptr(new detail::Dynamic_Cast_Conversion())); + } +} + + +#endif + diff --git a/unittests/inheritance_test.cpp b/unittests/inheritance_test.cpp new file mode 100644 index 0000000..70d795f --- /dev/null +++ b/unittests/inheritance_test.cpp @@ -0,0 +1,48 @@ +#include + +class Test +{ + public: + std::string function() { return "Function"; } +}; + +class Test2 : public Test +{ + public: + std::string function2() { return "Function2"; } +}; + +int main() +{ + + chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); + + CHAISCRIPT_CLASS( m, + Test, + (Test ()) + (Test (const Test &)), + ((function)) + ); + + CHAISCRIPT_CLASS( m, + Test2, + (Test2 ()) + (Test2 (const Test2 &)), + ((function2)) + ); + + chaiscript::ChaiScript chai; + + m->add(chaiscript::dynamic_cast_conversion()); + + + chai.add(m); + if (chai.eval("var t = Test2(); t.function(); ") == "Function" + && chai.eval("var t = Test2(); t.function2(); ") == "Function2") + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + +}