Eradicate global base_class registrations to prevent problems with threading and general memory management issues with knowing how and when to clean them up.

This commit is contained in:
Jason Turner 2013-02-25 11:00:14 -07:00
parent 1858885010
commit 2afc09dad4
16 changed files with 308 additions and 314 deletions

View File

@ -273,21 +273,6 @@ namespace chaiscript
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
/**
* Returns true if a call can be made that consists of the first parameter
* (the function) with the remaining parameters as its arguments.
*/
static Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{
if (params.size() < 1)
{
throw exception::arity_error(static_cast<int>(params.size()), 1);
}
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
}
static bool has_guard(const Const_Proxy_Function &t_pf) static bool has_guard(const Const_Proxy_Function &t_pf)
{ {
@ -383,7 +368,6 @@ namespace chaiscript
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation"); m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&dispatch::Proxy_Function_Base::operator()), "call");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
@ -476,9 +460,6 @@ namespace chaiscript
m->add(fun(&ptr_assign<boost::remove_const<dispatch::Proxy_Function_Base>::type>), "="); m->add(fun(&ptr_assign<boost::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<boost::add_const<dispatch::Proxy_Function_Base>::type>), "="); m->add(fun(&ptr_assign<boost::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
"call_exists");
m->add(fun(&type_match), "type_match"); m->add(fun(&type_match), "type_match");
return m; return m;

View File

@ -68,10 +68,10 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions = Dynamic_Cast_Conversions())
{ {
try { try {
return detail::Cast_Helper<Type>::cast(bv); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const boost::bad_any_cast &) { } catch (const boost::bad_any_cast &) {
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
@ -86,7 +86,7 @@ namespace chaiscript
try { try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // 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 // either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(detail::boxed_dynamic_cast<Type>(bv)); return detail::Cast_Helper<Type>::cast(t_conversions.boxed_dynamic_cast<Type>(bv), t_conversions);
} catch (const boost::bad_any_cast &) { } catch (const boost::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }

View File

@ -17,6 +17,8 @@
namespace chaiscript namespace chaiscript
{ {
class Dynamic_Cast_Conversions;
namespace detail namespace detail
{ {
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
@ -29,7 +31,7 @@ namespace chaiscript
{ {
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type; typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@ -71,7 +73,7 @@ namespace chaiscript
{ {
typedef const Result * Result_Type; typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@ -100,7 +102,7 @@ namespace chaiscript
{ {
typedef Result * Result_Type; typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@ -119,7 +121,7 @@ namespace chaiscript
{ {
typedef typename boost::reference_wrapper<Result> Result_Type; typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@ -138,7 +140,7 @@ namespace chaiscript
{ {
typedef typename boost::shared_ptr<Result> Result_Type; typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
return boost::any_cast<boost::shared_ptr<Result> >(ob.get()); return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
} }
@ -152,7 +154,7 @@ namespace chaiscript
{ {
typedef typename boost::shared_ptr<const Result> Result_Type; typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
if (!ob.get_type_info().is_const()) if (!ob.get_type_info().is_const())
{ {
@ -200,7 +202,7 @@ namespace chaiscript
{ {
typedef const Boxed_Value & Result_Type; typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
return ob; return ob;
} }
@ -261,9 +263,9 @@ namespace chaiscript
{ {
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type; typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &t_conversions)
{ {
return Cast_Helper_Inner<T>::cast(ob); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }
}; };
} }

View File

@ -820,7 +820,7 @@ namespace chaiscript
{ {
typedef Boxed_Number Result_Type; typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &)
{ {
return Boxed_Number(ob); return Boxed_Number(ob);
} }

View File

@ -222,9 +222,9 @@ namespace chaiscript
public: public:
Dispatch_Function(const std::vector<Proxy_Function> &t_funcs) Dispatch_Function(const std::vector<Proxy_Function> &t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs)), : Proxy_Function_Base(build_type_infos(t_funcs)),
m_funcs(t_funcs) m_funcs(t_funcs)
{ {
} }
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const
{ {
@ -274,7 +274,7 @@ namespace chaiscript
return -1; // unknown arity return -1; // unknown arity
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
typedef std::vector<Proxy_Function> function_vec; typedef std::vector<Proxy_Function> function_vec;
@ -283,7 +283,7 @@ namespace chaiscript
while (begin != end) while (begin != end)
{ {
if ((*begin)->call_match(vals)) if ((*begin)->call_match(vals, t_conversions))
{ {
return true; return true;
} else { } else {
@ -300,9 +300,9 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params); return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params, t_conversions);
} }
private: private:
@ -389,16 +389,21 @@ namespace chaiscript
~Dispatch_Engine() ~Dispatch_Engine()
{ {
detail::Dynamic_Conversions::get().cleanup(m_conversions.begin(), m_conversions.end());
} }
/// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{
return chaiscript::boxed_cast<Type>(bv, m_conversions);
}
/** /**
* Add a new conversion for upcasting to a base class * Add a new conversion for upcasting to a base class
*/ */
void add(const Dynamic_Cast_Conversion &d) void add(const Dynamic_Cast_Conversion &d)
{ {
m_conversions.push_back(d); m_conversions.add_conversion(d);
return detail::Dynamic_Conversions::get().add_conversion(d);
} }
/** /**
@ -771,11 +776,16 @@ namespace chaiscript
m_state.m_reserved_words.insert(name); m_state.m_reserved_words.insert(name);
} }
const Dynamic_Cast_Conversions &conversions() const
{
return m_conversions;
}
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{ {
std::vector<Proxy_Function> functions = get_function(t_name); std::vector<Proxy_Function> functions = get_function(t_name);
return dispatch::dispatch(functions.begin(), functions.end(), params); return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions);
} }
Boxed_Value call_function(const std::string &t_name) const Boxed_Value call_function(const std::string &t_name) const
@ -844,6 +854,22 @@ namespace chaiscript
std::cout << ") " << std::endl; std::cout << ") " << std::endl;
} }
/**
* Returns true if a call can be made that consists of the first parameter
* (the function) with the remaining parameters as its arguments.
*/
Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{
if (params.size() < 1)
{
throw exception::arity_error(static_cast<int>(params.size()), 1);
}
Const_Proxy_Function f = this->boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions));
}
/** /**
* Dump all system info to stdout * Dump all system info to stdout
*/ */
@ -1146,7 +1172,7 @@ namespace chaiscript
int call_depth; int call_depth;
}; };
std::vector<Dynamic_Cast_Conversion> m_conversions; Dynamic_Cast_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder; chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;

View File

@ -47,7 +47,7 @@ namespace chaiscript
class Dynamic_Conversion class Dynamic_Conversion
{ {
public: public:
virtual Boxed_Value convert(const Boxed_Value &derived) = 0; virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
const Type_Info &base() const Type_Info &base()
{ {
@ -73,7 +73,7 @@ namespace chaiscript
}; };
template<typename Base, typename Derived> template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion class Dynamic_Conversion_Impl : public Dynamic_Conversion
{ {
public: public:
Dynamic_Conversion_Impl() Dynamic_Conversion_Impl()
@ -81,7 +81,7 @@ namespace chaiscript
{ {
} }
virtual Boxed_Value convert(const Boxed_Value &t_derived) virtual Boxed_Value convert(const Boxed_Value &t_derived) const
{ {
if (t_derived.get_type_info().bare_equal(user_type<Derived>())) if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
{ {
@ -91,7 +91,7 @@ namespace chaiscript
if (t_derived.is_const()) if (t_derived.is_const())
{ {
boost::shared_ptr<const Base> data boost::shared_ptr<const Base> data
= boost::dynamic_pointer_cast<const Base>(detail::Cast_Helper<boost::shared_ptr<const Derived> >::cast(t_derived)); = boost::dynamic_pointer_cast<const Base>(detail::Cast_Helper<boost::shared_ptr<const Derived> >::cast(t_derived, Dynamic_Cast_Conversions()));
if (!data) if (!data)
{ {
throw std::bad_cast(); throw std::bad_cast();
@ -100,7 +100,7 @@ namespace chaiscript
return Boxed_Value(data); return Boxed_Value(data);
} else { } else {
boost::shared_ptr<Base> data boost::shared_ptr<Base> data
= boost::dynamic_pointer_cast<Base>(detail::Cast_Helper<boost::shared_ptr<Derived> >::cast(t_derived)); = boost::dynamic_pointer_cast<Base>(detail::Cast_Helper<boost::shared_ptr<Derived> >::cast(t_derived, Dynamic_Cast_Conversions()));
if (!data) if (!data)
{ {
@ -113,11 +113,11 @@ namespace chaiscript
// Pull the reference out of the contained boxed value, which we know is the type we want // Pull the reference out of the contained boxed value, which we know is the type we want
if (t_derived.is_const()) if (t_derived.is_const())
{ {
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived); const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived, Dynamic_Cast_Conversions());
const Base &data = dynamic_cast<const Base &>(d); const Base &data = dynamic_cast<const Base &>(d);
return Boxed_Value(boost::cref(data)); return Boxed_Value(boost::cref(data));
} else { } else {
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived); Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived, Dynamic_Cast_Conversions());
Base &data = dynamic_cast<Base &>(d); Base &data = dynamic_cast<Base &>(d);
return Boxed_Value(boost::ref(data)); return Boxed_Value(boost::ref(data));
} }
@ -127,101 +127,98 @@ namespace chaiscript
} }
} }
}; };
class Dynamic_Conversions
{
public:
static inline Dynamic_Conversions &get()
{
static Dynamic_Conversions obj;
return obj;
}
template<typename Base, typename Derived>
static boost::shared_ptr<Dynamic_Conversion> create()
{
boost::shared_ptr<Dynamic_Conversion> conversion(new Dynamic_Conversion_Impl<Base, Derived>());
/// \todo this is a hack and a kludge. The idea is to make sure that
/// the conversion is registered both in the module's notion of the static conversion object
/// and in the global notion of the static conversion object
/// someday this will almost certainly have to change. Maybe it is time for ChaiScript
/// to become a library?
Dynamic_Conversions::get().add_conversion(conversion);
return conversion;
}
template<typename InItr>
void cleanup(InItr begin, const InItr &end)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
while (begin != end)
{
if (begin->unique())
{
m_conversions.erase(begin->get());
}
++begin;
}
}
void add_conversion(const boost::shared_ptr<Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion.get());
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<Dynamic_Conversion *>::const_iterator 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:
Dynamic_Conversions() {}
std::set<Dynamic_Conversion *>::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<Dynamic_Conversion *>::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<Dynamic_Conversion *> m_conversions;
};
} }
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 boost::shared_ptr<detail::Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion);
}
template<typename Base, typename Derived>
bool dynamic_cast_converts() const
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
return has_conversion(base, derived);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
{
try {
return get_conversion(user_type<Base>(), 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");
}
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
boost::shared_ptr<detail::Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator 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<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
std::set<boost::shared_ptr<detail::Dynamic_Conversion> > get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<boost::shared_ptr<detail::Dynamic_Conversion> > m_conversions;
};
typedef boost::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion; typedef boost::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you /// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
@ -248,42 +245,17 @@ namespace chaiscript
/// \todo Move share static type registration code into a mechanism that allows it to be properly /// \todo Move share static type registration code into a mechanism that allows it to be properly
/// shared by all modules /// shared by all modules
template<typename Base, typename Derived> template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class() 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
BOOST_STATIC_ASSERT((boost::is_base_of<Base,Derived>::value));
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
return detail::Dynamic_Conversions::create<Base, Derived>();
}
namespace detail
{
template<typename Base, typename Derived>
bool dynamic_cast_converts()
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
{ {
return detail::Dynamic_Conversions::get().has_conversion(base, derived); //Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
BOOST_STATIC_ASSERT((boost::is_base_of<Base,Derived>::value));
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
return boost::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
} }
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
{
try {
return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), 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");
}
}
}
} }

View File

@ -57,11 +57,11 @@ namespace chaiscript
const Proxy_Function &t_func, const Proxy_Function &t_func,
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>()) const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
: 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)),
m_type_name(t_type_name), m_func(t_func), m_ti(t_ti) m_type_name(t_type_name), m_func(t_func), m_ti(t_ti)
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
} }
virtual ~Dynamic_Object_Function() {} virtual ~Dynamic_Object_Function() {}
@ -76,11 +76,11 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
if (dynamic_object_typename_match(vals, m_type_name, m_ti)) if (dynamic_object_typename_match(vals, m_type_name, m_ti))
{ {
return m_func->call_match(vals); return m_func->call_match(vals, t_conversions);
} else { } else {
return false; return false;
} }
@ -106,11 +106,11 @@ namespace chaiscript
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti)) if (dynamic_object_typename_match(params, m_type_name, m_ti))
{ {
return (*m_func)(params); return (*m_func)(params, t_conversions);
} else { } else {
throw exception::guard_error(); throw exception::guard_error();
} }
@ -192,11 +192,11 @@ namespace chaiscript
const std::string &t_type_name, const std::string &t_type_name,
const Proxy_Function &t_func) 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())),
m_type_name(t_type_name), m_func(t_func) m_type_name(t_type_name), m_func(t_func)
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
} }
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl) static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{ {
@ -224,13 +224,13 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
std::vector<Boxed_Value> new_vals; std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name))); new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end()); new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals); return m_func->call_match(new_vals, t_conversions);
} }
@ -246,14 +246,14 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
std::vector<Boxed_Value> new_params; std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv); new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end()); new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params); (*m_func)(new_params, t_conversions);
return bv; return bv;
} }

View File

@ -15,65 +15,65 @@ namespace chaiscript
{ {
struct Exception_Handler_Base struct Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
protected: protected:
template<typename T> template<typename T>
void throw_type(const Boxed_Value &bv) void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
try { T t = boxed_cast<T>(bv); throw t; } catch (const exception::bad_boxed_cast &) {} try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const exception::bad_boxed_cast &) {}
} }
}; };
template<typename T1> template<typename T1>
struct Exception_Handler_Impl1 : Exception_Handler_Base struct Exception_Handler_Impl1 : Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
throw_type<T1>(bv); throw_type<T1>(bv, t_engine);
} }
}; };
template<typename T1, typename T2> template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base struct Exception_Handler_Impl2 : Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
throw_type<T1>(bv); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv); throw_type<T2>(bv, t_engine);
} }
}; };
template<typename T1, typename T2, typename T3> template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base struct Exception_Handler_Impl3 : Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
throw_type<T1>(bv); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv); throw_type<T2>(bv, t_engine);
throw_type<T3>(bv); throw_type<T3>(bv, t_engine);
} }
}; };
template<typename T1, typename T2, typename T3, typename T4> template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base struct Exception_Handler_Impl4 : Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
throw_type<T1>(bv); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv); throw_type<T2>(bv, t_engine);
throw_type<T3>(bv); throw_type<T3>(bv, t_engine);
throw_type<T4>(bv); throw_type<T4>(bv, t_engine);
} }
}; };
template<typename T1, typename T2, typename T3, typename T4, typename T5> template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base struct Exception_Handler_Impl5 : Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{ {
throw_type<T1>(bv); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv); throw_type<T2>(bv, t_engine);
throw_type<T3>(bv); throw_type<T3>(bv, t_engine);
throw_type<T4>(bv); throw_type<T4>(bv, t_engine);
throw_type<T5>(bv); throw_type<T5>(bv, t_engine);
} }
}; };
} }

View File

@ -32,10 +32,10 @@ namespace chaiscript
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs) functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions &t_conversions)
{ {
FunctionType *p=0; FunctionType *p=0;
return detail::build_function_caller_helper(p, funcs); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
/** /**
@ -53,11 +53,11 @@ namespace chaiscript
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
functor(Const_Proxy_Function func) functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions &t_conversions)
{ {
std::vector<Const_Proxy_Function> funcs; std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func); funcs.push_back(func);
return functor<FunctionType>(funcs); return functor<FunctionType>(funcs, t_conversions);
} }
/** /**
@ -66,9 +66,9 @@ namespace chaiscript
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
functor(const Boxed_Value &bv) functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions)
{ {
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv)); return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
} }
} }
@ -81,13 +81,13 @@ namespace chaiscript
{ {
typedef boost::function<Signature> Result_Type; typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
return dispatch::functor<Signature>(ob); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const boost::function<Signature> &>::cast(ob); return Cast_Helper_Inner<const boost::function<Signature> &>::cast(ob, t_conversions);
} }
} }
}; };
@ -100,13 +100,13 @@ namespace chaiscript
{ {
typedef boost::function<Signature> Result_Type; typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
return dispatch::functor<Signature>(ob); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<boost::function<Signature> >::cast(ob); return Cast_Helper_Inner<boost::function<Signature> >::cast(ob, t_conversions);
} }
} }
}; };
@ -119,13 +119,13 @@ namespace chaiscript
{ {
typedef boost::function<Signature> Result_Type; typedef boost::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob) static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions &t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
return dispatch::functor<Signature>(ob); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const boost::function<Signature> >::cast(ob); return Cast_Helper_Inner<const boost::function<Signature> >::cast(ob, t_conversions);
} }
} }
}; };

View File

@ -36,9 +36,9 @@ namespace chaiscript
struct Function_Caller_Ret struct Function_Caller_Ret
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params) const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{ {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params)); return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
} }
}; };
@ -49,9 +49,9 @@ namespace chaiscript
struct Function_Caller_Ret<void> struct Function_Caller_Ret<void>
{ {
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params) const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{ {
dispatch::dispatch(t_funcs, params); dispatch::dispatch(t_funcs, params, t_conversions);
} }
}; };
} }
@ -76,14 +76,14 @@ namespace chaiscript
* used internally for unwrapping a function call's types * used internally for unwrapping a function call's types
*/ */
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) > template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<Const_Proxy_Function> &funcs Ret function_caller(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions &t_conversions
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) ) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{ {
std::vector<Boxed_Value> params; std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~) BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>::call(funcs, params); return Function_Caller_Ret<Ret>::call(funcs, params, t_conversions);
} }
/** /**
@ -91,7 +91,8 @@ namespace chaiscript
*/ */
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) > template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) > boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<Const_Proxy_Function> &funcs) build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<Const_Proxy_Function> &funcs,
const Dynamic_Cast_Conversions &t_conversions)
{ {
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
@ -107,7 +108,7 @@ namespace chaiscript
// we cannot make any other guesses or assumptions really, so continuing // we cannot make any other guesses or assumptions really, so continuing
} }
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs, t_conversions
BOOST_PP_ENUM_TRAILING(n, curry, ~)); BOOST_PP_ENUM_TRAILING(n, curry, ~));
} }
} }

View File

@ -70,9 +70,9 @@ namespace chaiscript
{ {
public: public:
virtual ~Proxy_Function_Base() {} virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params) const Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const
{ {
Boxed_Value bv = do_call(params); Boxed_Value bv = do_call(params, t_conversions);
return bv; return bv;
} }
@ -83,7 +83,7 @@ namespace chaiscript
std::vector<Type_Info> get_param_types() const { return m_types; } std::vector<Type_Info> get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0;
bool has_arithmetic_param() const bool has_arithmetic_param() const
{ {
@ -98,7 +98,7 @@ namespace chaiscript
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals) const bool filter(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
int arity = get_arity(); int arity = get_arity();
@ -110,7 +110,7 @@ namespace chaiscript
{ {
return true; return true;
} else { } else {
return compare_first_type(vals[0]); return compare_first_type(vals[0], t_conversions);
} }
} else { } else {
return false; return false;
@ -122,15 +122,15 @@ namespace chaiscript
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv) static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions)
{ {
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
|| (!bv.get_type_info().is_undef() || (!bv.get_type_info().is_undef()
&& (ti.bare_equal(user_type<Boxed_Number>()) && (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| chaiscript::detail::dynamic_cast_converts(ti, bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<boost::shared_ptr<const Proxy_Function_Base> >()) || bv.get_type_info().bare_equal(user_type<boost::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info())
) )
) )
) )
@ -141,7 +141,7 @@ namespace chaiscript
} }
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types) Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types), m_has_arithmetic_param(false) : m_types(t_types), m_has_arithmetic_param(false)
@ -157,7 +157,7 @@ namespace chaiscript
} }
virtual bool compare_first_type(const Boxed_Value &bv) const virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const
{ {
const std::vector<Type_Info> &types = get_param_types(); const std::vector<Type_Info> &types = get_param_types();
@ -167,11 +167,11 @@ namespace chaiscript
} }
const Type_Info &ti = types[1]; const Type_Info &ti = types[1];
return compare_type_to_param(ti, bv); return compare_type_to_param(ti, bv, t_conversions);
} }
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
{ {
if (tis.size() - 1 != bvs.size()) if (tis.size() - 1 != bvs.size())
{ {
@ -247,10 +247,10 @@ namespace chaiscript
&& !this->m_guard && !prhs->m_guard); && !this->m_guard && !prhs->m_guard);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
return (m_arity < 0 || vals.size() == size_t(m_arity)) return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals); && test_guard(vals, t_conversions);
} }
virtual ~Dynamic_Proxy_Function() {} virtual ~Dynamic_Proxy_Function() {}
@ -277,12 +277,12 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
if (m_arity < 0 || params.size() == size_t(m_arity)) if (m_arity < 0 || params.size() == size_t(m_arity))
{ {
if (test_guard(params)) if (test_guard(params, t_conversions))
{ {
return m_f(params); return m_f(params);
} else { } else {
@ -295,12 +295,12 @@ namespace chaiscript
} }
private: private:
bool test_guard(const std::vector<Boxed_Value> &params) const bool test_guard(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
if (m_guard) if (m_guard)
{ {
try { try {
return boxed_cast<bool>((*m_guard)(params)); return boxed_cast<bool>((*m_guard)(params, t_conversions));
} catch (const exception::arity_error &) { } catch (const exception::arity_error &) {
return false; return false;
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
@ -356,7 +356,7 @@ namespace chaiscript
Bound_Function(const Const_Proxy_Function &t_f, Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args) const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(build_param_type_info(t_f, 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<int>(get_param_types().size())-1) m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1)
{ {
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size())); assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
} }
@ -368,14 +368,9 @@ namespace chaiscript
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
return m_f->call_match(build_param_list(vals)); return m_f->call_match(build_param_list(vals), t_conversions);
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
return (*m_f)(build_param_list(params));
} }
virtual std::vector<Const_Proxy_Function> get_contained_functions() const virtual std::vector<Const_Proxy_Function> get_contained_functions() const
@ -452,9 +447,9 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
return (*m_f)(build_param_list(params)); return (*m_f)(build_param_list(params), t_conversions);
} }
private: private:
@ -475,8 +470,8 @@ namespace chaiscript
Proxy_Function_Impl(const boost::function<Func> &f) Proxy_Function_Impl(const boost::function<Func> &f)
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(0))), : Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(0))),
m_f(f), m_dummy_func(0) m_f(f), m_dummy_func(0)
{ {
} }
virtual ~Proxy_Function_Impl() {} virtual ~Proxy_Function_Impl() {}
@ -493,14 +488,14 @@ namespace chaiscript
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{ {
if (int(vals.size()) != get_arity()) if (int(vals.size()) != get_arity())
{ {
return false; return false;
} }
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals); return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals, t_conversions);
} }
virtual std::string annotation() const virtual std::string annotation() const
@ -514,9 +509,9 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
return detail::Do_Call<typename boost::function<Func>::result_type>::go(m_f, params); return detail::Do_Call<typename boost::function<Func>::result_type>::go(m_f, params, t_conversions);
} }
private: private:
@ -534,8 +529,8 @@ namespace chaiscript
Attribute_Access(T Class::* t_attr) Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()), : Proxy_Function_Base(param_types()),
m_attr(t_attr) m_attr(t_attr)
{ {
} }
virtual ~Attribute_Access() {} virtual ~Attribute_Access() {}
@ -556,7 +551,7 @@ namespace chaiscript
return 1; return 1;
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &) const
{ {
if (vals.size() != 1) if (vals.size() != 1)
{ {
@ -572,17 +567,17 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{ {
if (params.size() == 1) if (params.size() == 1)
{ {
const Boxed_Value &bv = params[0]; const Boxed_Value &bv = params[0];
if (bv.is_const()) if (bv.is_const())
{ {
const Class *o = boxed_cast<const Class *>(bv); const Class *o = boxed_cast<const Class *>(bv, t_conversions);
return detail::Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr); return detail::Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
} else { } else {
Class *o = boxed_cast<Class *>(bv); Class *o = boxed_cast<Class *>(bv, t_conversions);
return detail::Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr); return detail::Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
} }
} else { } else {
@ -630,7 +625,8 @@ namespace chaiscript
namespace detail namespace detail
{ {
template<typename FuncType> template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist) bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions)
{ {
if (t_func->get_arity() != plist.size()) if (t_func->get_arity() != plist.size())
{ {
@ -643,7 +639,7 @@ namespace chaiscript
for (int i = 0; i < plist.size(); ++i) for (int i = 0; i < plist.size(); ++i)
{ {
if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i]) if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i], t_conversions)
|| (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic())) || (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic()))
{ {
// types continue to match // types continue to match
@ -657,7 +653,8 @@ namespace chaiscript
} }
template<typename InItr> template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist) Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions)
{ {
InItr orig(begin); InItr orig(begin);
@ -665,7 +662,7 @@ namespace chaiscript
while (begin != end) while (begin != end)
{ {
if (types_match_except_for_arithmetic(*begin, plist)) if (types_match_except_for_arithmetic(*begin, plist, t_conversions))
{ {
if (matching_func == end) if (matching_func == end)
{ {
@ -700,7 +697,7 @@ namespace chaiscript
} }
try { try {
return (*(*matching_func))(newplist); return (*(*matching_func))(newplist, t_conversions);
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
//parameter failed to cast //parameter failed to cast
} catch (const exception::arity_error &) { } catch (const exception::arity_error &) {
@ -721,15 +718,15 @@ namespace chaiscript
*/ */
template<typename InItr> template<typename InItr>
Boxed_Value dispatch(InItr begin, const InItr &end, Boxed_Value dispatch(InItr begin, const InItr &end,
const std::vector<Boxed_Value> &plist) const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{ {
InItr orig(begin); InItr orig(begin);
while (begin != end) while (begin != end)
{ {
try { try {
if ((*begin)->filter(plist)) if ((*begin)->filter(plist, t_conversions))
{ {
return (*(*begin))(plist); return (*(*begin))(plist, t_conversions);
} }
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
//parameter failed to cast, try again //parameter failed to cast, try again
@ -742,7 +739,7 @@ namespace chaiscript
++begin; ++begin;
} }
return detail::dispatch_with_conversions(orig, end, plist); return detail::dispatch_with_conversions(orig, end, plist, t_conversions);
} }
/** /**
@ -752,9 +749,9 @@ namespace chaiscript
*/ */
template<typename Funcs> template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist) const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{ {
return dispatch::dispatch(funcs.begin(), funcs.end(), plist); return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions);
} }
} }
} }

View File

@ -7,8 +7,8 @@
#include <boost/preprocessor.hpp> #include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(chaiscript::detail::Get_Type_Info<Param ## n>::get()); #define gettypeinfo(z,n,text) ti.push_back(chaiscript::detail::Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) BOOST_PP_COMMA_IF(n) chaiscript::boxed_cast< Param ## n >(params[n]) #define casthelper(z,n,text) BOOST_PP_COMMA_IF(n) chaiscript::boxed_cast< Param ## n >(params[n], t_conversions)
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]); #define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n], t_conversions);
#ifndef BOOST_PP_IS_ITERATING #ifndef BOOST_PP_IS_ITERATING
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
@ -88,7 +88,7 @@ namespace chaiscript
*/ */
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)> template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f, Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params) const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions & BOOST_PP_IF(n, t_conversions, ))
{ {
if (params.size() != n) if (params.size() != n)
{ {
@ -105,7 +105,7 @@ namespace chaiscript
*/ */
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)> template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)), bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, )) const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, ), const Dynamic_Cast_Conversions &t_conversions)
{ {
try { try {
BOOST_PP_REPEAT(n, trycast, ~); BOOST_PP_REPEAT(n, trycast, ~);
@ -140,9 +140,9 @@ namespace chaiscript
struct Do_Call struct Do_Call
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params) static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{ {
return Handle_Return<Ret>::handle(call_func(fun, params)); return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
} }
}; };
@ -150,9 +150,9 @@ namespace chaiscript
struct Do_Call<void> struct Do_Call<void>
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params) static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{ {
call_func(fun, params); call_func(fun, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();
} }
}; };

View File

@ -334,6 +334,13 @@ namespace chaiscript
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, boost::ref(m_engine)), "get_functions"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, boost::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, boost::ref(m_engine)), "get_objects"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, boost::ref(m_engine)), "get_objects");
m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(boost::bind(&chaiscript::detail::Dispatch_Engine::call_exists, boost::ref(m_engine), _1))),
"call_exists");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(boost::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), _1, _2, boost::ref(m_engine.conversions()))), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name");
@ -665,7 +672,7 @@ namespace chaiscript
return do_eval(t_script); return do_eval(t_script);
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv, m_engine);
} }
throw bv; throw bv;
} }
@ -688,15 +695,23 @@ namespace chaiscript
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__") T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{ {
try { try {
return boxed_cast<T>(do_eval(t_input, t_filename)); return m_engine.boxed_cast<T>(do_eval(t_input, t_filename));
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv, m_engine);
} }
throw bv; throw bv;
} }
} }
/// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
{
return m_engine.boxed_cast<Type>(bv);
}
/// \brief Evaluates a string. /// \brief Evaluates a string.
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
@ -713,7 +728,7 @@ namespace chaiscript
return do_eval(t_input, t_filename); return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv, m_engine);
} }
throw bv; throw bv;
} }
@ -729,7 +744,7 @@ namespace chaiscript
return do_eval(load_file(t_filename), t_filename); return do_eval(load_file(t_filename), t_filename);
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv, m_engine);
} }
throw bv; throw bv;
} }
@ -746,10 +761,10 @@ namespace chaiscript
template<typename T> template<typename T>
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) { T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
try { try {
return boxed_cast<T>(do_eval(load_file(t_filename), t_filename)); return m_engine.boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
if (t_handler) { if (t_handler) {
t_handler->handle(bv); t_handler->handle(bv, m_engine);
} }
throw bv; throw bv;
} }

View File

@ -225,7 +225,7 @@ namespace chaiscript
try { try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(plb); const Boxed_Value &retval = (*t_ss.boxed_cast<const Const_Proxy_Function &>(fn))(plb, t_ss.conversions());
return retval; return retval;
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
@ -233,7 +233,7 @@ namespace chaiscript
} }
catch(const exception::bad_boxed_cast &){ catch(const exception::bad_boxed_cast &){
try { try {
Const_Proxy_Function f = boxed_cast<const Const_Proxy_Function &>(fn); Const_Proxy_Function f = t_ss.boxed_cast<const Const_Proxy_Function &>(fn);
// handle the case where there is only 1 function to try to call and dispatch fails on it // handle the case where there is only 1 function to try to call and dispatch fails on it
std::vector<Const_Proxy_Function> funcs; std::vector<Const_Proxy_Function> funcs;
funcs.push_back(f); funcs.push_back(f);
@ -293,11 +293,11 @@ namespace chaiscript
try { try {
bv = this->children[0]->eval(t_ss); bv = this->children[0]->eval(t_ss);
try { try {
fn = boxed_cast<const Const_Proxy_Function &>(bv); fn = t_ss.boxed_cast<const Const_Proxy_Function &>(bv);
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function."); throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
} }
return (*fn)(plb); return (*fn)(plb, t_ss.conversions());
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss); throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
@ -1026,7 +1026,7 @@ namespace chaiscript
std::map<std::string, Boxed_Value> retval; std::map<std::string, Boxed_Value> retval;
for (size_t i = 0; i < this->children[0]->children.size(); ++i) { for (size_t i = 0; i < this->children[0]->children.size(); ++i) {
Boxed_Value bv = t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss)); Boxed_Value bv = t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss));
retval[boxed_cast<std::string>(this->children[0]->children[i]->children[0]->eval(t_ss))] retval[t_ss.boxed_cast<std::string>(this->children[0]->children[i]->children[0]->eval(t_ss))]
= bv; = bv;
} }
return const_var(retval); return const_var(retval);

View File

@ -43,9 +43,9 @@ struct System
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks; std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name, void add_callback(const std::string &t_name,
const chaiscript::Proxy_Function &t_func) const boost::function<std::string (const std::string &)> &t_func)
{ {
m_callbacks[t_name] = chaiscript::dispatch::functor<std::string (const std::string &)>(t_func); m_callbacks[t_name] = t_func;
} }

View File

@ -9,7 +9,7 @@ int test_generic()
try { try {
chai.eval("throw(runtime_error(\"error\"));"); chai.eval("throw(runtime_error(\"error\"));");
} catch (const chaiscript::Boxed_Value &bv) { } catch (const chaiscript::Boxed_Value &bv) {
const std::exception &e = chaiscript::boxed_cast<const std::exception &>(bv); const std::exception &e = chai.boxed_cast<const std::exception &>(bv);
if (e.what() == std::string("error")) if (e.what() == std::string("error"))
{ {
return EXIT_SUCCESS; return EXIT_SUCCESS;