Allow conversions while calling chaiscript funcs
* This puts ChaiScript funcs more on even footings with C++ defined funcs * Minor performance hit (0.5%)
This commit is contained in:
@@ -72,10 +72,51 @@ namespace chaiscript
|
|||||||
return m_types == t_rhs.m_types;
|
return m_types == t_rhs.m_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const
|
||||||
{
|
{
|
||||||
if (!m_has_types) { return true; }
|
for (size_t i = 0; i < vals.size(); ++i)
|
||||||
if (vals.size() != m_types.size()) { return false; }
|
{
|
||||||
|
const auto &name = m_types[i].first;
|
||||||
|
if (!name.empty()) {
|
||||||
|
const auto &bv = vals[i];
|
||||||
|
|
||||||
|
if (!bv.get_type_info().bare_equal(m_doti))
|
||||||
|
{
|
||||||
|
const auto &ti = m_types[i].second;
|
||||||
|
if (!ti.is_undef())
|
||||||
|
{
|
||||||
|
if (!bv.get_type_info().bare_equal(ti)) {
|
||||||
|
if (t_conversions->converts(ti, bv.get_type_info())) {
|
||||||
|
try {
|
||||||
|
// 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
|
||||||
|
vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
|
||||||
|
} catch (...) {
|
||||||
|
try {
|
||||||
|
// try going the other way
|
||||||
|
vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
|
||||||
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
|
throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first result: is a match
|
||||||
|
// second result: needs conversions
|
||||||
|
std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
||||||
|
{
|
||||||
|
bool needs_conversion = false;
|
||||||
|
|
||||||
|
if (!m_has_types) { return std::make_pair(true, needs_conversion); }
|
||||||
|
if (vals.size() != m_types.size()) { return std::make_pair(false, needs_conversion); }
|
||||||
|
|
||||||
for (size_t i = 0; i < vals.size(); ++i)
|
for (size_t i = 0; i < vals.size(); ++i)
|
||||||
{
|
{
|
||||||
@@ -87,25 +128,31 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
||||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
if (!(name == "Dynamic_Object" || d.get_type_name() == name)) {
|
||||||
|
return std::make_pair(false, false);
|
||||||
|
}
|
||||||
} catch (const std::bad_cast &) {
|
} catch (const std::bad_cast &) {
|
||||||
return false;
|
return std::make_pair(false, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const auto &ti = m_types[i].second;
|
const auto &ti = m_types[i].second;
|
||||||
if (!ti.is_undef())
|
if (!ti.is_undef())
|
||||||
{
|
{
|
||||||
if (!bv.get_type_info().bare_equal(ti)) {
|
if (!bv.get_type_info().bare_equal(ti)) {
|
||||||
return false;
|
if (!t_conversions->converts(ti, bv.get_type_info())) {
|
||||||
|
return std::make_pair(false, false);
|
||||||
|
} else {
|
||||||
|
needs_conversion = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return std::make_pair(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return std::make_pair(true, needs_conversion);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::pair<std::string, Type_Info>> &types() const
|
const std::vector<std::pair<std::string, Type_Info>> &types() const
|
||||||
@@ -320,8 +367,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||||
{
|
{
|
||||||
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
|
return call_match_internal(vals, t_conversions).first;
|
||||||
&& test_guard(vals, t_conversions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -353,6 +399,26 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first result: is a match
|
||||||
|
// second result: needs conversions
|
||||||
|
std::pair<bool, bool> call_match_internal(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
||||||
|
{
|
||||||
|
const auto comparison_result = [&](){
|
||||||
|
if (m_arity < 0) {
|
||||||
|
return std::make_pair(true, false);
|
||||||
|
} else if (vals.size() == size_t(m_arity)) {
|
||||||
|
return m_param_types.match(vals, t_conversions);
|
||||||
|
} else {
|
||||||
|
return std::make_pair(false, false);
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
return std::make_pair(
|
||||||
|
comparison_result.first && test_guard(vals, t_conversions),
|
||||||
|
comparison_result.second
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
||||||
{
|
{
|
||||||
@@ -371,7 +437,10 @@ namespace chaiscript
|
|||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
Param_Types m_param_types;
|
Param_Types m_param_types;
|
||||||
|
|
||||||
|
private:
|
||||||
Proxy_Function m_guard;
|
Proxy_Function m_guard;
|
||||||
AST_NodePtr m_parsenode;
|
AST_NodePtr m_parsenode;
|
||||||
};
|
};
|
||||||
@@ -402,9 +471,14 @@ namespace chaiscript
|
|||||||
protected:
|
protected:
|
||||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||||
{
|
{
|
||||||
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
|
const auto match_results = call_match_internal(params, t_conversions);
|
||||||
|
if (match_results.first)
|
||||||
{
|
{
|
||||||
return m_f(params);
|
if (match_results.second) {
|
||||||
|
return m_f(m_param_types.convert(params, t_conversions));
|
||||||
|
} else {
|
||||||
|
return m_f(params);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw exception::guard_error();
|
throw exception::guard_error();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,28 +397,39 @@ namespace chaiscript
|
|||||||
template<typename To>
|
template<typename To>
|
||||||
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
|
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
|
||||||
{
|
{
|
||||||
try {
|
return boxed_type_conversion(user_type<To>(), t_saves, from);
|
||||||
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
|
|
||||||
if (t_saves.enabled) { t_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<typename From>
|
template<typename From>
|
||||||
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
|
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
|
||||||
|
{
|
||||||
|
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
|
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
|
||||||
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
|
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
|
||||||
return ret;
|
return ret;
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
|
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
|
||||||
} catch (const std::bad_cast &) {
|
} catch (const std::bad_cast &) {
|
||||||
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
|
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
|
||||||
|
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
|
||||||
|
return ret;
|
||||||
|
} catch (const std::out_of_range &) {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
|
||||||
|
} catch (const std::bad_cast &) {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1226,7 +1226,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
if (dispatch::Param_Types(
|
if (dispatch::Param_Types(
|
||||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(catch_block->children[0], t_ss)}
|
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(catch_block->children[0], t_ss)}
|
||||||
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
|
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first)
|
||||||
{
|
{
|
||||||
t_ss.add_object(name, t_except);
|
t_ss.add_object(name, t_except);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user