diff --git a/CMakeLists.txt b/CMakeLists.txt index 3917f0cf..50066fcf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,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") @@ -175,7 +175,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/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; } 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 31d93865..1fc57558 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -14,11 +14,11 @@ #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 { -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); @@ -86,18 +86,18 @@ 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; // 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/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 b49d14cc..9d785079 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" @@ -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) @@ -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()) { @@ -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,9 +312,9 @@ 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); + return dispatch::dispatch(m_funcs, params, t_conversions); } private: @@ -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,16 +768,14 @@ namespace chaiscript m_state.m_reserved_words.insert(name); } - const Dynamic_Cast_Conversions &conversions() const + const Type_Conversions &conversions() const { return m_conversions; } 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 @@ -917,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; @@ -925,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() @@ -940,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); } } @@ -1138,7 +1161,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 deleted file mode 100644 index 184246ef..00000000 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ /dev/null @@ -1,289 +0,0 @@ -// This file is distributed under the BSD License. -// See "license.txt" for details. -// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) -// Copyright 2009-2014, Jason Turner (jason@emptycrate.com) -// http://www.chaiscript.com - -#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ -#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ - -#include -#include -#include -#include -#include -#include - -#include "../chaiscript_threading.hpp" -#include "bad_boxed_cast.hpp" -#include "boxed_cast_helper.hpp" -#include "boxed_value.hpp" -#include "type_info.hpp" - -namespace chaiscript -{ - namespace exception - { - class bad_boxed_dynamic_cast : public bad_boxed_cast - { - public: - bad_boxed_dynamic_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) - { - } - - bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT - : bad_boxed_cast(t_from, t_to) - { - } - - bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT - : bad_boxed_cast(w) - { - } - - virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} - }; - } - - namespace detail - { - class Dynamic_Conversion - { - 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 - { - return m_base; - } - const Type_Info &derived() const - { - return m_derived; - } - - protected: - Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived) - : m_base(t_base), m_derived(t_derived) - { - } - - virtual ~Dynamic_Conversion() {} - - private: - Type_Info m_base; - Type_Info m_derived; - - }; - - template - class Dynamic_Caster - { - public: - static Boxed_Value cast(const Boxed_Value &t_from) - { - if (t_from.get_type_info().bare_equal(user_type())) - { - if (t_from.is_pointer()) - { - // Dynamic cast out the contained boxed value, which we know is the type we want - if (t_from.is_const()) - { - std::shared_ptr data - = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); - if (!data) - { - throw std::bad_cast(); - } - - return Boxed_Value(data); - } else { - std::shared_ptr data - = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); - - if (!data) - { - throw std::bad_cast(); - } - - return Boxed_Value(data); - } - } else { - // Pull the reference out of the contained boxed value, which we know is the type we want - if (t_from.is_const()) - { - const From &d = detail::Cast_Helper::cast(t_from, nullptr); - const To &data = dynamic_cast(d); - return Boxed_Value(std::cref(data)); - } else { - From &d = detail::Cast_Helper::cast(t_from, nullptr); - To &data = dynamic_cast(d); - return Boxed_Value(std::ref(data)); - } - } - } else { - throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); - } - } - }; - - template - class Dynamic_Conversion_Impl : public Dynamic_Conversion - { - public: - Dynamic_Conversion_Impl() - : Dynamic_Conversion(user_type(), user_type()) - { - } - - virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE - { - return Dynamic_Caster::cast(t_base); - } - - virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE - { - return Dynamic_Caster::cast(t_derived); - } - }; - } - - class Dynamic_Cast_Conversions - { - public: - Dynamic_Cast_Conversions() - { - } - - Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other) - : m_conversions(t_other.get_conversions()) - { - } - - 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 - { - return dynamic_cast_converts(user_type(), user_type()); - } - - bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const - { - return has_conversion(base, derived) || has_conversion(derived, base); - } - - template - Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const - { - try { - return get_conversion(user_type(), derived.get_type_info())->convert(derived); - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "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"); - } - } - - template - Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const - { - try { - return get_conversion(base.get_type_info(), user_type())->convert_down(base); - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "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"); - } - } - - - bool has_conversion(const Type_Info &base, const Type_Info &derived) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - return find(base, derived) != m_conversions.end(); - } - - std::shared_ptr get_conversion(const Type_Info &base, const Type_Info &derived) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - auto itr = - find(base, derived); - - 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()); - } - } - - private: - std::set >::const_iterator find( - const Type_Info &base, const Type_Info &derived) const - { - return std::find_if(m_conversions.begin(), m_conversions.end(), - [&base, &derived](const std::shared_ptr &conversion) - { - return conversion->base().bare_equal(base) && conversion->derived().bare_equal(derived); - } - ); - } - - std::set > get_conversions() const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - return m_conversions; - } - - mutable chaiscript::detail::threading::shared_mutex m_mutex; - std::set > m_conversions; - }; - - typedef std::shared_ptr Dynamic_Cast_Conversion; - - /// \brief Used to register a base / 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 - /// 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 - /// relationship in all modules that use the newly added type in a polymorphic way. - /// - /// Example: - /// \code - /// class Base - /// {}; - /// class Derived : public Base - /// {}; - /// - /// chaiscript::ChaiScript chai; - /// chai.add(chaiscript::base_class()); - /// \endcode - /// - template - Dynamic_Cast_Conversion base_class() - { - //Can only be used with related polymorphic types - //may be expanded some day to support conversions other than child -> parent - static_assert(std::is_base_of::value, "Classes are not related by inheritance"); - 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()); - } - -} - - -#endif diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 5c932408..69c24d51 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 @@ -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) @@ -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)) { @@ -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(); @@ -134,7 +128,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 +138,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 +156,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 +178,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) { @@ -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) @@ -248,7 +242,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()); @@ -256,20 +250,13 @@ 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(); } 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..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 @@ -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/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/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 16ceaf8e..fba9b4ff 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,15 +82,13 @@ 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(); - - 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,11 +100,14 @@ 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; - 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 +115,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,10 +126,10 @@ 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) + 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) { @@ -141,7 +142,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(); @@ -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)) { } @@ -233,16 +234,12 @@ 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); } - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - return m_arity; - } Proxy_Function get_guard() const { @@ -260,7 +257,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 +275,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) { @@ -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())); } @@ -351,7 +348,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); } @@ -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(); @@ -429,7 +421,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); } @@ -437,30 +429,24 @@ 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)) + Proxy_Function_Impl_Base(const std::vector &t_types) + : Proxy_Function_Base(t_types, static_cast(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 ""; } - 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 +456,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 +476,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 +492,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); } @@ -524,8 +510,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,13 +529,7 @@ namespace chaiscript } } - - virtual int get_arity() const CHAISCRIPT_OVERRIDE - { - 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 +545,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 +602,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 +630,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); @@ -712,17 +692,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, - const std::vector &plist, const Dynamic_Cast_Conversions &t_conversions) + 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) + { + size_t numdiffs = 0; + const auto arity = func->get_arity(); + + if (arity == -1) + { + numdiffs = 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())) + { + ++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 +737,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 Dynamic_Cast_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); } } } 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/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp new file mode 100644 index 00000000..b238b972 --- /dev/null +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -0,0 +1,447 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2014, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ +#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include "../chaiscript_threading.hpp" +#include "bad_boxed_cast.hpp" +#include "boxed_cast_helper.hpp" +#include "boxed_value.hpp" +#include "type_info.hpp" + +namespace chaiscript +{ + namespace exception + { + class bad_boxed_dynamic_cast : public bad_boxed_cast + { + public: + bad_boxed_dynamic_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) + { + } + + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to) + { + } + + bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(w) + { + } + + virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} + }; + + class bad_boxed_type_cast : public bad_boxed_cast + { + public: + 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) + { + } + + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT + : bad_boxed_cast(t_from, t_to) + { + } + + 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: + Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) + : m_to(t_to), m_from(t_from) + { + } + + virtual ~Type_Conversion_Base() {} + + private: + Type_Info m_to; + Type_Info m_from; + + }; + + template + class Dynamic_Caster + { + public: + static Boxed_Value cast(const Boxed_Value &t_from) + { + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) + { + if (t_from.is_pointer()) + { + // Dynamic cast out the contained boxed value, which we know is the type we want + if (t_from.is_const()) + { + std::shared_ptr data + = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); + if (!data) + { + throw std::bad_cast(); + } + + return Boxed_Value(data); + } else { + std::shared_ptr data + = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr)); + + if (!data) + { + throw std::bad_cast(); + } + + return Boxed_Value(data); + } + } else { + // Pull the reference out of the contained boxed value, which we know is the type we want + if (t_from.is_const()) + { + const From &d = detail::Cast_Helper::cast(t_from, nullptr); + const To &data = dynamic_cast(d); + return Boxed_Value(std::cref(data)); + } else { + From &d = detail::Cast_Helper::cast(t_from, nullptr); + To &data = dynamic_cast(d); + return Boxed_Value(std::ref(data)); + } + } + } else { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); + } + } + }; + + template + class Dynamic_Conversion_Impl : public Type_Conversion_Base + { + public: + Dynamic_Conversion_Impl() + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) + { + } + + virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE + { + return Dynamic_Caster::cast(t_base); + } + + virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE + { + return Dynamic_Caster::cast(t_derived); + } + }; + + + template + class Type_Conversion_Impl : public Type_Conversion_Base + { + public: + 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)) + { + } + + 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: + Callable m_func; + }; + + } + + 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), + 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_conversion_saves(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 + { + return converts(user_type(), user_type()); + } + + 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(from.bare_type_info()) != 0) + { + return has_conversion(to, from) || has_conversion(from, to); + } else { + return false; + } + + } + + template + Boxed_Value boxed_type_conversion(const Boxed_Value &from) const + { + try { + 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 &) { + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation"); + } + } + + template + Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const + { + try { + 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 &) { + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation"); + } + } + + 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 + { + chaiscript::detail::threading::shared_lock l(m_mutex); + return find(to, from) != m_conversions.end(); + } + + 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(to, from); + + if (itr != m_conversions.end()) + { + return *itr; + } else { + 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 &to, const Type_Info &from) const + { + return std::find_if(m_conversions.begin(), m_conversions.end(), + [&to, &from](const std::shared_ptr &conversion) + { + return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); + } + ); + } + + std::set> get_conversions() const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + return m_conversions; + } + + + struct Conversion_Saves + { + Conversion_Saves() + : enabled(false) + {} + + bool enabled; + 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; + + /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you + /// want automatic conversions up your inheritance hierarchy. + /// + /// 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 type + /// relationship in all modules that use the newly added type in a polymorphic way. + /// + /// Example: + /// \code + /// class Base + /// {}; + /// class Derived : public Base + /// {}; + /// + /// chaiscript::ChaiScript chai; + /// chai.add(chaiscript::to_class()); + /// \endcode + /// + template + Type_Conversion base_class() + { + //Can only be used with related polymorphic types + //may be expanded some day to support conversions other than child -> parent + static_assert(std::is_base_of::value, "Classes are not related by inheritance"); + static_assert(std::is_polymorphic::value, "Base class must be polymorphic"); + static_assert(std::is_polymorphic::value, "Derived class must be polymorphic"); + + return std::make_shared>(); + } + + template + Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, + const Callable &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); + } + + 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 + 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); + } + +} + + +#endif 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; 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/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 539157c8..b5393c54 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&); @@ -679,7 +686,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; 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) ) { diff --git a/src/test_module.cpp b/src/test_module.cpp index 7b6ff75c..cb95326a 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -2,6 +2,8 @@ #include #include + + class TestBaseType { public: @@ -22,6 +24,30 @@ class TestBaseType TestBaseType &operator=(const TestBaseType &); }; +class Type2 +{ + public: + Type2(TestBaseType t_bt) + : m_bt(std::move(t_bt)), + m_str("Hello World") + { + } + + int get_val() const + { + return m_bt.val; + } + + const char *get_str() const + { + return m_str.c_str(); + } + + private: + TestBaseType m_bt; + std::string m_str; +}; + enum TestEnum { TestValue1 = 1 @@ -95,6 +121,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,6 +162,12 @@ 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"); + 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.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"); + + + diff --git a/unittests/user_defined_conversions_2.chai b/unittests/user_defined_conversions_2.chai new file mode 100644 index 00000000..fdb601ca --- /dev/null +++ b/unittests/user_defined_conversions_2.chai @@ -0,0 +1,27 @@ +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); +//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"); + +