10 #ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_ 11 #define CHAISCRIPT_PROXY_FUNCTIONS_HPP_ 19 #include <type_traits> 22 #include "../chaiscript_defines.hpp" 23 #include "boxed_cast.hpp" 24 #include "boxed_value.hpp" 25 #include "dynamic_object.hpp" 26 #include "function_params.hpp" 27 #include "proxy_functions_detail.hpp" 28 #include "type_info.hpp" 31 class Type_Conversions;
45 template<
typename FunctionType>
46 std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func,
const Type_Conversions_State *t_conversions);
51 : m_has_types(
false) {
54 explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
55 : m_types(std::move(t_types))
56 , m_has_types(
false) {
60 void push_front(std::string t_name,
Type_Info t_ti) {
61 m_types.emplace(m_types.begin(), std::move(t_name), t_ti);
65 bool operator==(
const Param_Types &t_rhs)
const noexcept {
return m_types == t_rhs.m_types; }
68 auto vals = t_params.to_vector();
69 const auto dynamic_object_type_info = user_type<Dynamic_Object>();
70 for (
size_t i = 0; i < vals.size(); ++i) {
71 const auto &name = m_types[i].first;
73 const auto &bv = vals[i];
75 if (!bv.get_type_info().bare_equal(dynamic_object_type_info)) {
76 const auto &ti = m_types[i].second;
78 if (!bv.get_type_info().bare_equal(ti)) {
79 if (t_conversions->converts(ti, bv.get_type_info())) {
83 vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
87 vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
105 const auto dynamic_object_type_info = user_type<Dynamic_Object>();
106 bool needs_conversion =
false;
109 return std::make_pair(
true, needs_conversion);
111 if (vals.size() != m_types.size()) {
112 return std::make_pair(
false, needs_conversion);
115 for (
size_t i = 0; i < vals.size(); ++i) {
116 const auto &name = m_types[i].first;
118 const auto &bv = vals[i];
120 if (bv.get_type_info().bare_equal(dynamic_object_type_info)) {
123 if (!(name ==
"Dynamic_Object" || d.get_type_name() == name)) {
124 return std::make_pair(
false,
false);
126 }
catch (
const std::bad_cast &) {
127 return std::make_pair(
false,
false);
130 const auto &ti = m_types[i].second;
131 if (!ti.is_undef()) {
132 if (!bv.get_type_info().bare_equal(ti)) {
133 if (!t_conversions->converts(ti, bv.get_type_info())) {
134 return std::make_pair(
false,
false);
136 needs_conversion =
true;
140 return std::make_pair(
false,
false);
146 return std::make_pair(
true, needs_conversion);
149 const std::vector<std::pair<std::string, Type_Info>> &types()
const noexcept {
return m_types; }
152 void update_has_types() {
153 for (
const auto &type : m_types) {
154 if (!type.first.empty()) {
163 std::vector<std::pair<std::string, Type_Info>> m_types;
180 if (m_arity < 0 ||
size_t(m_arity) == params.size()) {
181 return do_call(params, t_conversions);
196 virtual bool is_attribute_function()
const noexcept {
return false; }
198 bool has_arithmetic_param()
const noexcept {
return m_has_arithmetic_param; }
200 virtual std::vector<std::shared_ptr<const Proxy_Function_Base>> get_contained_functions()
const {
201 return std::vector<std::shared_ptr<const Proxy_Function_Base>>();
207 assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
211 }
else if (m_arity > 1) {
212 return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
214 return compare_type_to_param(m_types[1], vals[0], t_conversions);
222 const auto boxed_value_ti = user_type<Boxed_Value>();
223 const auto boxed_number_ti = user_type<Boxed_Number>();
224 const auto function_ti = user_type<std::shared_ptr<const Proxy_Function_Base>>();
226 if (ti.is_undef() || ti.bare_equal(boxed_value_ti)
227 || (!bv.get_type_info().is_undef()
228 && ((ti.bare_equal(boxed_number_ti) && bv.get_type_info().is_arithmetic()) || ti.bare_equal(bv.get_type_info())
229 || bv.get_type_info().bare_equal(function_ti) || t_conversions->converts(ti, bv.get_type_info())))) {
238 return compare_type_to_param(m_types[1], bv, t_conversions);
245 : m_types(std::move(t_types))
247 , m_has_arithmetic_param(
false) {
248 for (
size_t i = 1; i < m_types.size(); ++i) {
249 if (m_types[i].is_arithmetic()) {
250 m_has_arithmetic_param =
true;
257 if (tis.size() - 1 != bvs.size()) {
260 const size_t size = bvs.size();
261 for (
size_t i = 0; i < size; ++i) {
262 if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) {
270 std::vector<Type_Info> m_types;
272 bool m_has_arithmetic_param;
283 namespace exception {
288 : std::runtime_error(
"Guard evaluation failed") {
303 std::shared_ptr<AST_Node> t_parsenode,
307 , m_param_types(std::move(t_param_types))
308 , m_guard(std::move(t_guard))
309 , m_parsenode(std::move(t_parsenode)) {
317 || ((prhs !=
nullptr) && this->m_arity == prhs->m_arity && !this->m_guard && !prhs->m_guard
318 && this->m_param_types == prhs->m_param_types);
322 return call_match_internal(vals, t_conversions).first;
325 bool has_guard()
const noexcept {
return bool(m_guard); }
329 bool has_parse_tree()
const noexcept {
return static_cast<bool>(m_parsenode); }
331 const AST_Node &get_parse_tree()
const {
335 throw std::runtime_error(
"Dynamic_Proxy_Function does not have parse_tree");
343 return boxed_cast<
bool>((*m_guard)(params, t_conversions));
357 const auto comparison_result = [&]() {
359 return std::make_pair(
true,
false);
360 }
else if (vals.size() == size_t(m_arity)) {
361 return m_param_types.match(vals, t_conversions);
363 return std::make_pair(
false,
false);
367 return std::make_pair(comparison_result.first && test_guard(vals, t_conversions), comparison_result.second);
371 static std::vector<Type_Info> build_param_type_list(
const Param_Types &t_types) {
375 for (
const auto &t : t_types.types()) {
376 if (t.second.is_undef()) {
379 types.push_back(t.second);
391 std::shared_ptr<AST_Node> m_parsenode;
394 template<
typename Callable>
399 std::shared_ptr<AST_Node> t_parsenode =
AST_NodePtr(),
403 , m_f(std::move(t_f)) {
408 const auto [is_a_match, needs_conversions] = call_match_internal(params, t_conversions);
410 if (needs_conversions) {
411 return m_f(
Function_Params{m_param_types.convert(params, t_conversions)});
424 template<
typename Callable,
typename... Arg>
425 Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg &&...a) {
426 return chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function_Impl<Callable>>(std::forward<Callable>(c),
427 std::forward<Arg>(a)...);
443 (t_f->get_arity() < 0 ? -1 :
static_cast<int>(build_param_type_info(t_f, t_args).size()) - 1))
446 assert(m_f->get_arity() < 0 || m_f->get_arity() ==
static_cast<int>(m_args.size()));
449 bool operator==(
const Proxy_Function_Base &t_f)
const noexcept
override {
return &t_f ==
this; }
452 return m_f->call_match(
Function_Params(build_param_list(vals)), t_conversions);
455 std::vector<Const_Proxy_Function> get_contained_functions()
const override {
return std::vector<Const_Proxy_Function>{m_f}; }
457 std::vector<Boxed_Value> build_param_list(
const Function_Params ¶ms)
const {
458 auto parg = params.begin();
459 auto barg = m_args.begin();
461 std::vector<Boxed_Value> args;
463 while (!(parg == params.end() && barg == m_args.end())) {
465 args.push_back(*barg);
469 if (parg != params.end()) {
470 args.push_back(*parg);
482 static std::vector<Type_Info> build_param_type_info(
const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args) {
483 assert(t_f->get_arity() < 0 || t_f->get_arity() ==
static_cast<int>(t_args.size()));
485 if (t_f->get_arity() < 0) {
486 return std::vector<Type_Info>();
489 const auto types = t_f->get_param_types();
490 assert(types.size() == t_args.size() + 1);
493 std::vector<Type_Info> retval{types[0]};
495 for (
size_t i = 0; i < types.size() - 1; ++i) {
497 retval.push_back(types[i + 1]);
505 return (*m_f)(
Function_Params{build_param_list(params)}, t_conversions);
510 std::vector<Boxed_Value> m_args;
520 return static_cast<int>(vals.size()) == get_arity()
521 && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
528 template<
typename Func,
typename Callable>
533 , m_f(std::move(f)) {
537 return detail::compare_types_cast(static_cast<Func *>(
nullptr), vals, t_conversions);
546 return detail::call_func(static_cast<Func *>(
nullptr), m_f, params, t_conversions);
559 virtual void assign(
const std::shared_ptr<const Proxy_Function_Base> &t_rhs) = 0;
562 template<
typename Func>
567 , m_f(std::move(t_f))
568 , m_shared_ptr_holder(std::move(t_ptr)) {
569 assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
573 return detail::compare_types_cast(static_cast<Func *>(
nullptr), vals, t_conversions);
580 std::function<Func> internal_function()
const {
return m_f.get(); }
582 void assign(
const std::shared_ptr<const Proxy_Function_Base> &t_rhs)
override { m_f.get() = dispatch::functor<Func>(t_rhs,
nullptr); }
586 return detail::call_func(static_cast<Func *>(
nullptr), m_f.get(), params, t_conversions);
590 std::reference_wrapper<std::function<Func>> m_f;
591 std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
595 template<
typename T,
typename Class>
603 bool is_attribute_function()
const noexcept
override {
return true; }
609 return m_attr == aa->m_attr;
616 if (vals.size() != 1) {
619 const auto class_type_info = user_type<Class>();
620 return vals[0].get_type_info().bare_equal(class_type_info);
627 const Class *o =
boxed_cast<
const Class *>(bv, &t_conversions);
628 return do_call_impl<T>(o);
630 Class *o =
boxed_cast<Class *>(bv, &t_conversions);
631 return do_call_impl<T>(o);
636 template<
typename Type>
637 auto do_call_impl(Class *o)
const {
638 if constexpr (std::is_pointer<Type>::value) {
645 template<
typename Type>
646 auto do_call_impl(
const Class *o)
const {
647 if constexpr (std::is_pointer<Type>::value) {
654 static std::vector<Type_Info> param_types() {
return {user_type<T>(), user_type<Class>()}; }
656 std::vector<Type_Info> m_param_types{user_type<T>(), user_type<Class>()};
661 namespace exception {
670 : std::runtime_error(
"Error with function dispatch")
671 , parameters(t_parameters.to_vector())
672 , functions(std::move(t_functions)) {
676 : std::runtime_error(t_desc)
677 , parameters(t_parameters.to_vector())
678 , functions(std::move(t_functions)) {
684 std::vector<Boxed_Value> parameters;
685 std::vector<Const_Proxy_Function> functions;
691 template<
typename FuncType>
692 bool types_match_except_for_arithmetic(
const FuncType &t_func,
695 const std::vector<Type_Info> &types = t_func->get_param_types();
697 if (t_func->get_arity() == -1) {
701 assert(plist.size() == types.size() - 1);
703 return std::mismatch(plist.begin(),
707 return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions)
708 || (bv.get_type_info().is_arithmetic() && ti.is_arithmetic());
710 == std::make_pair(plist.end(), types.end());
713 template<
typename InItr,
typename Funcs>
718 const Funcs &t_funcs) {
719 InItr matching_func(end);
721 while (begin != end) {
722 if (types_match_except_for_arithmetic(begin->second, plist, t_conversions)) {
723 if (matching_func == end) {
724 matching_func = begin;
727 const auto &mat_fun_param_types = matching_func->second->get_param_types();
728 const auto &next_fun_param_types = begin->second->get_param_types();
730 if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
731 matching_func = begin;
732 }
else if (!plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
744 if (matching_func == end) {
749 std::vector<Boxed_Value> newplist;
750 newplist.reserve(plist.size());
752 const std::vector<Type_Info> &tis = matching_func->second->get_param_types();
753 std::transform(tis.begin() + 1, tis.end(), plist.begin(), std::back_inserter(newplist), [](
const Type_Info &ti,
const Boxed_Value ¶m) ->
Boxed_Value {
754 if (ti.is_arithmetic() && param.get_type_info().is_arithmetic() && param.get_type_info() != ti) {
778 template<
typename Funcs>
780 std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
781 ordered_funcs.reserve(funcs.size());
783 for (
const auto &func : funcs) {
784 const auto arity = func->get_arity();
787 ordered_funcs.emplace_back(plist.size(), func.get());
788 }
else if (arity == static_cast<int>(plist.size())) {
790 for (
size_t i = 0; i < plist.size(); ++i) {
791 if (!func->get_param_types()[i + 1].bare_equal(plist[i].get_type_info())) {
795 ordered_funcs.emplace_back(numdiffs, func.get());
799 for (
size_t i = 0; i <= plist.size(); ++i) {
800 for (
const auto &func : ordered_funcs) {
802 if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions))) {
803 return (*(func.second))(plist, t_conversions);
816 return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs);
Compile time deduced information about a type.
Definition: type_info.hpp:27
const std::vector< Type_Info > & get_param_types() const noexcept
Returns a vector containing all of the types of the parameters the function returns/takes if the func...
Definition: proxy_functions.hpp:191
Helper used to create a Type_Info object.
Definition: type_info.hpp:106
Definition: proxy_functions.hpp:553
bool filter(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept
Return true if the function is a possible match to the passed in values.
Definition: proxy_functions.hpp:206
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions=nullptr)
Function for extracting a value stored in a Boxed_Value object.
Definition: boxed_cast.hpp:71
Definition: type_conversions.hpp:417
Exception thrown if a function's guard fails.
Definition: proxy_functions.hpp:285
Namespace chaiscript contains every API call that the average user will be concerned with...
Definition: function_params.hpp:16
Definition: proxy_functions.hpp:395
An object used by Bound_Function to represent "_" parameters of a binding.
Definition: proxy_functions.hpp:432
An implementation of Proxy_Function that takes a Proxy_Function and substitutes bound parameters into...
Definition: proxy_functions.hpp:439
Pure virtual base class for all Proxy_Function implementations Proxy_Functions are a type erasure of ...
Definition: proxy_functions.hpp:175
A wrapper for holding any valid C++ type.
Definition: boxed_value.hpp:24
Thrown in the event that a Boxed_Value cannot be cast to the desired type.
Definition: bad_boxed_cast.hpp:31
Definition: proxy_functions.hpp:48
Definition: handle_return.hpp:29
Boxed_Value dispatch(const Funcs &funcs, const Function_Params &plist, const Type_Conversions_State &t_conversions)
Take a vector of functions and a vector of parameters.
Definition: proxy_functions.hpp:779
Used internally for handling a return value from a Proxy_Function call.
Definition: handle_return.hpp:34
Struct that doubles as both a parser ast_node and an AST node.
Definition: chaiscript_common.hpp:174
std::shared_ptr< const dispatch::Proxy_Function_Base > Const_Proxy_Function
Const version of Proxy_Function.
Definition: proxy_functions.hpp:281
Exception thrown when there is a mismatch in number of parameters during Proxy_Function execution...
Definition: proxy_functions_detail.hpp:38
std::shared_ptr< dispatch::Proxy_Function_Base > Proxy_Function
Common typedef used for passing of any registered function in ChaiScript.
Definition: proxy_functions.hpp:277
int get_arity() const noexcept
Definition: proxy_functions.hpp:219
Definition: dynamic_object.hpp:38
Thrown in the event that an Any cannot be cast to the desired type.
Definition: any.hpp:20
Attribute getter Proxy_Function implementation.
Definition: proxy_functions.hpp:596
Exception thrown in the case that a method dispatch fails because no matching function was found...
Definition: proxy_functions.hpp:667
Represents any numeric type, generically. Used internally for generic operations between POD values...
Definition: boxed_number.hpp:60
Definition: proxy_functions.hpp:513
std::unique_ptr< AST_Node > AST_NodePtr
Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree.
Definition: proxy_functions.hpp:42
For any callable object.
Definition: handle_return.hpp:27
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept
Definition: proxy_functions.hpp:236
A Proxy_Function implementation that is not type safe, the called function is expecting a vector<Boxe...
Definition: proxy_functions.hpp:300