GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
proxy_functions.hpp
Go to the documentation of this file.
1// This file is distributed under the BSD License.
2// See "license.txt" for details.
3// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
5// http://www.chaiscript.com
6
7// This is an open source non-commercial project. Dear PVS-Studio, please check it.
8// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
9
10
11#ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_
12#define CHAISCRIPT_PROXY_FUNCTIONS_HPP_
13
14
15#include <cassert>
16#include <functional>
17#include <memory>
18#include <stdexcept>
19#include <string>
20#include <type_traits>
21#include <vector>
22#include <iterator>
23
25#include "boxed_cast.hpp"
26#include "boxed_value.hpp"
28#include "type_info.hpp"
29#include "dynamic_object.hpp"
30
31namespace chaiscript {
33namespace exception {
34class bad_boxed_cast;
35struct arity_error;
36} // namespace exception
37} // namespace chaiscript
38
39namespace chaiscript
40{
41 class Boxed_Number;
42 struct AST_Node;
43
44 typedef std::unique_ptr<AST_Node> AST_NodePtr;
45
46 namespace dispatch
47 {
48 template<typename FunctionType>
49 std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions_State *t_conversions);
50
52 {
53 public:
55 : m_has_types(false),
56 m_doti(user_type<Dynamic_Object>())
57 {}
58
59 explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
60 : m_types(std::move(t_types)),
61 m_has_types(false),
62 m_doti(user_type<Dynamic_Object>())
63 {
64 update_has_types();
65 }
66
67 void push_front(std::string t_name, Type_Info t_ti)
68 {
69 m_types.emplace(m_types.begin(), std::move(t_name), t_ti);
70 update_has_types();
71 }
72
73 bool operator==(const Param_Types &t_rhs) const
74 {
75 return m_types == t_rhs.m_types;
76 }
77
78 std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const
79 {
80 for (size_t i = 0; i < vals.size(); ++i)
81 {
82 const auto &name = m_types[i].first;
83 if (!name.empty()) {
84 const auto &bv = vals[i];
85
86 if (!bv.get_type_info().bare_equal(m_doti))
87 {
88 const auto &ti = m_types[i].second;
89 if (!ti.is_undef())
90 {
91 if (!bv.get_type_info().bare_equal(ti)) {
92 if (t_conversions->converts(ti, bv.get_type_info())) {
93 try {
94 // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
95 // either way, we are not responsible if it doesn't work
96 vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
97 } catch (...) {
98 try {
99 // try going the other way
100 vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
102 throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info());
103 }
104 }
105 }
106 }
107 }
108 }
109 }
110 }
111
112 return vals;
113 }
114
115 // first result: is a match
116 // second result: needs conversions
117 std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
118 {
119 bool needs_conversion = false;
120
121 if (!m_has_types) { return std::make_pair(true, needs_conversion); }
122 if (vals.size() != m_types.size()) { return std::make_pair(false, needs_conversion); }
123
124 for (size_t i = 0; i < vals.size(); ++i)
125 {
126 const auto &name = m_types[i].first;
127 if (!name.empty()) {
128 const auto &bv = vals[i];
129
130 if (bv.get_type_info().bare_equal(m_doti))
131 {
132 try {
133 const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
134 if (!(name == "Dynamic_Object" || d.get_type_name() == name)) {
135 return std::make_pair(false, false);
136 }
137 } catch (const std::bad_cast &) {
138 return std::make_pair(false, false);
139 }
140 } else {
141 const auto &ti = m_types[i].second;
142 if (!ti.is_undef())
143 {
144 if (!bv.get_type_info().bare_equal(ti)) {
145 if (!t_conversions->converts(ti, bv.get_type_info())) {
146 return std::make_pair(false, false);
147 } else {
148 needs_conversion = true;
149 }
150 }
151 } else {
152 return std::make_pair(false, false);
153 }
154 }
155 }
156 }
157
158 return std::make_pair(true, needs_conversion);
159 }
160
161 const std::vector<std::pair<std::string, Type_Info>> &types() const
162 {
163 return m_types;
164 }
165
166 private:
167 void update_has_types()
168 {
169 for (const auto &type : m_types)
170 {
171 if (!type.first.empty())
172 {
173 m_has_types = true;
174 return;
175 }
176 }
177
178 m_has_types = false;
179 }
180
181 std::vector<std::pair<std::string, Type_Info>> m_types;
182 bool m_has_types;
183 Type_Info m_doti;
184
185 };
186
196 {
197 public:
198 virtual ~Proxy_Function_Base() = default;
199
200 Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions_State &t_conversions) const
201 {
202 if (m_arity < 0 || size_t(m_arity) == params.size()) {
203 return do_call(params, t_conversions);
204 } else {
205 throw exception::arity_error(static_cast<int>(params.size()), m_arity);
206 }
207 }
208
213 const std::vector<Type_Info> &get_param_types() const { return m_types; }
214
215 virtual bool operator==(const Proxy_Function_Base &) const = 0;
216 virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
217
218 virtual bool is_attribute_function() const { return false; }
219
221 {
223 }
224
225 virtual std::vector<std::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
226 {
227 return std::vector<std::shared_ptr<const Proxy_Function_Base> >();
228 }
229
232 bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
233 {
234 assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
235
236 if (m_arity < 0)
237 {
238 return true;
239 } else if (m_arity > 1) {
240 return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
241 } else {
242 return compare_type_to_param(m_types[1], vals[0], t_conversions);
243 }
244 }
245
247 int get_arity() const
248 {
249 return m_arity;
250 }
251
252 static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
253 {
254 if (ti.is_undef()
256 || (!bv.get_type_info().is_undef()
258 || ti.bare_equal(bv.get_type_info())
259 || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
260 || t_conversions->converts(ti, bv.get_type_info())
261 )
262 )
263 )
264 {
265 return true;
266 } else {
267 return false;
268 }
269 }
270
271 virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const
272 {
273 return compare_type_to_param(m_types[1], bv, t_conversions);
274 }
275
276 protected:
277 virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const = 0;
278
279 Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
280 : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
281 {
282 for (size_t i = 1; i < m_types.size(); ++i)
283 {
284 if (m_types[i].is_arithmetic())
285 {
287 return;
288 }
289 }
290
291 }
292
293
294 static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs,
295 const Type_Conversions_State &t_conversions)
296 {
297 if (tis.size() - 1 != bvs.size())
298 {
299 return false;
300 } else {
301 const size_t size = bvs.size();
302 for (size_t i = 0; i < size; ++i)
303 {
304 if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; }
305 }
306 }
307 return true;
308 }
309
310 std::vector<Type_Info> m_types;
313 };
314 }
315
317 typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
318
321 typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
322
323 namespace exception
324 {
326 class guard_error : public std::runtime_error
327 {
328 public:
329 guard_error() noexcept
330 : std::runtime_error("Guard evaluation failed")
331 { }
332
333 guard_error(const guard_error &) = default;
334
335 ~guard_error() noexcept override = default;
336 };
337 }
338
339 namespace dispatch
340 {
346 {
347 public:
349 const int t_arity,
350 std::shared_ptr<AST_Node> t_parsenode,
351 Param_Types t_param_types = Param_Types(),
352 Proxy_Function t_guard = Proxy_Function())
353 : Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
354 m_param_types(std::move(t_param_types)),
355 m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
356 {
357 // assert(t_parsenode);
358 }
359
360
361 bool operator==(const Proxy_Function_Base &rhs) const override
362 {
363 const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
364
365 return this == &rhs
366 || ((prhs != nullptr)
367 && this->m_arity == prhs->m_arity
368 && !this->m_guard && !prhs->m_guard
369 && this->m_param_types == prhs->m_param_types);
370 }
371
372 bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
373 {
374 return call_match_internal(vals, t_conversions).first;
375 }
376
377
379 {
380 return m_guard;
381 }
382
383 bool has_parse_tree() const {
384 return static_cast<bool>(m_parsenode);
385 }
386
388 {
389 if (m_parsenode) {
390 return *m_parsenode;
391 } else {
392 throw std::runtime_error("Dynamic_Proxy_Function does not have parse_tree");
393 }
394 }
395
396
397 protected:
398 bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const
399 {
400 if (m_guard)
401 {
402 try {
403 return boxed_cast<bool>((*m_guard)(params, t_conversions));
404 } catch (const exception::arity_error &) {
405 return false;
406 } catch (const exception::bad_boxed_cast &) {
407 return false;
408 }
409 } else {
410 return true;
411 }
412 }
413
414 // first result: is a match
415 // second result: needs conversions
416 std::pair<bool, bool> call_match_internal(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
417 {
418 const auto comparison_result = [&](){
419 if (m_arity < 0) {
420 return std::make_pair(true, false);
421 } else if (vals.size() == size_t(m_arity)) {
422 return m_param_types.match(vals, t_conversions);
423 } else {
424 return std::make_pair(false, false);
425 }
426 }();
427
428 return std::make_pair(
429 comparison_result.first && test_guard(vals, t_conversions),
430 comparison_result.second
431 );
432 }
433
434 private:
435 static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
436 {
437 // For the return type
438 std::vector<Type_Info> types{chaiscript::detail::Get_Type_Info<Boxed_Value>::get()};
439
440 for (const auto &t : t_types.types())
441 {
442 if (t.second.is_undef()) {
444 } else {
445 types.push_back(t.second);
446 }
447 }
448
449 return types;
450 }
451
452 protected:
454
455 private:
456 Proxy_Function m_guard;
457 std::shared_ptr<AST_Node> m_parsenode;
458 };
459
460
461
462 template<typename Callable>
464 {
465 public:
467 Callable t_f,
468 int t_arity=-1,
469 std::shared_ptr<AST_Node> t_parsenode = AST_NodePtr(),
470 Param_Types t_param_types = Param_Types(),
471 Proxy_Function t_guard = Proxy_Function())
473 t_arity,
474 std::move(t_parsenode),
475 std::move(t_param_types),
476 std::move(t_guard)
477 ),
478 m_f(std::move(t_f))
479 {
480 }
481
482
483 protected:
484 Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
485 {
486 const auto match_results = call_match_internal(params, t_conversions);
487 if (match_results.first)
488 {
489 if (match_results.second) {
490 return m_f(m_param_types.convert(params, t_conversions));
491 } else {
492 return m_f(params);
493 }
494 } else {
496 }
497 }
498
499 private:
500 Callable m_f;
501 };
502
503 template<typename Callable, typename ... Arg>
505 {
507 std::forward<Callable>(c), std::forward<Arg>(a)...);
508 }
509
513 {
514 };
515
521 {
522 public:
524 const std::vector<Boxed_Value> &t_args)
525 : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast<int>(build_param_type_info(t_f, t_args).size())-1)),
526 m_f(t_f), m_args(t_args)
527 {
528 assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
529 }
530
531 bool operator==(const Proxy_Function_Base &t_f) const override
532 {
533 return &t_f == this;
534 }
535
536
537 bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
538 {
539 return m_f->call_match(build_param_list(vals), t_conversions);
540 }
541
542 std::vector<Const_Proxy_Function> get_contained_functions() const override
543 {
544 return std::vector<Const_Proxy_Function>{m_f};
545 }
546
547
548 std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const
549 {
550 auto parg = params.begin();
551 auto barg = m_args.begin();
552
553 std::vector<Boxed_Value> args;
554
555 while (!(parg == params.end() && barg == m_args.end()))
556 {
557 while (barg != m_args.end()
558 && !(barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get()))
559 {
560 args.push_back(*barg);
561 ++barg;
562 }
563
564 if (parg != params.end())
565 {
566 args.push_back(*parg);
567 ++parg;
568 }
569
570 if (barg != m_args.end()
572 {
573 ++barg;
574 }
575 }
576 return args;
577 }
578
579
580 protected:
581 static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
582 const std::vector<Boxed_Value> &t_args)
583 {
584 assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast<int>(t_args.size()));
585
586 if (t_f->get_arity() < 0) { return std::vector<Type_Info>(); }
587
588 const auto types = t_f->get_param_types();
589 assert(types.size() == t_args.size() + 1);
590
591 // this analysis warning is invalid in MSVC12 and doesn't exist in MSVC14
592 std::vector<Type_Info> retval{types[0]};
593
594 for (size_t i = 0; i < types.size() - 1; ++i)
595 {
596 if (t_args[i].get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get())
597 {
598 retval.push_back(types[i+1]);
599 }
600 }
601
602 return retval;
603 }
604
605 Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
606 {
607 return (*m_f)(build_param_list(params), t_conversions);
608 }
609
610 private:
612 std::vector<Boxed_Value> m_args;
613 };
614
616 {
617 public:
618 explicit Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
619 : Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
620 {
621 }
622
623 bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
624 {
625 return static_cast<int>(vals.size()) == get_arity()
626 && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
627 }
628
629 virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
630 };
631
632
633
635 template<typename Func, typename Callable>
637 {
638 public:
640 : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
641 m_f(std::move(f))
642 {
643 }
644
645 bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
646 {
647 return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
648 }
649
650 bool operator==(const Proxy_Function_Base &t_func) const override
651 {
652 return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr;
653 }
654
655
656 protected:
657 Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
658 {
659 return detail::call_func(detail::Function_Signature<Func>(), m_f, params, t_conversions);
660 }
661
662 private:
663 Callable m_f;
664 };
665
666
668 {
669 public:
670 explicit Assignable_Proxy_Function(const std::vector<Type_Info> &t_types)
671 : Proxy_Function_Impl_Base(t_types)
672 {
673 }
674
675 virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) = 0;
676 };
677
678 template<typename Func>
680 {
681 public:
682 Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr)
683 : Assignable_Proxy_Function(detail::build_param_type_list(static_cast<Func *>(nullptr))),
684 m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr))
685 {
686 assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
687 }
688
689 bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
690 {
691 return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
692 }
693
694 bool operator==(const Proxy_Function_Base &t_func) const override
695 {
696 return dynamic_cast<const Assignable_Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
697 }
698
699 std::function<Func> internal_function() const
700 {
701 return m_f.get();
702 }
703
704 void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) override {
705 m_f.get() = dispatch::functor<Func>(t_rhs, nullptr);
706 }
707
708 protected:
709 Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
710 {
711 return detail::call_func(detail::Function_Signature<Func>(), m_f.get(), params, t_conversions);
712 }
713
714
715 private:
716 std::reference_wrapper<std::function<Func>> m_f;
717 std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
718 };
719
720
722 template<typename T, typename Class>
724 {
725 public:
726 explicit Attribute_Access(T Class::* t_attr)
727 : Proxy_Function_Base(param_types(), 1),
728 m_attr(t_attr)
729 {
730 }
731
732 bool is_attribute_function() const override { return true; }
733
734 bool operator==(const Proxy_Function_Base &t_func) const override
735 {
737 = dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
738
739 if (aa) {
740 return m_attr == aa->m_attr;
741 } else {
742 return false;
743 }
744 }
745
746 bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const override
747 {
748 if (vals.size() != 1)
749 {
750 return false;
751 }
752
753 return vals[0].get_type_info().bare_equal(user_type<Class>());
754 }
755
756 protected:
757 Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
758 {
759 const Boxed_Value &bv = params[0];
760 if (bv.is_const())
761 {
762 const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
763 return do_call_impl<T>(o);
764 } else {
765 Class *o = boxed_cast<Class *>(bv, &t_conversions);
766 return do_call_impl<T>(o);
767 }
768 }
769
770 private:
771 template<typename Type>
772 auto do_call_impl(Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
773 {
774 return detail::Handle_Return<Type>::handle(o->*m_attr);
775 }
776
777 template<typename Type>
778 auto do_call_impl(const Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
779 {
780 return detail::Handle_Return<const Type>::handle(o->*m_attr);
781 }
782
783 template<typename Type>
784 auto do_call_impl(Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
785 {
786 return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
787 }
788
789 template<typename Type>
790 auto do_call_impl(const Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
791 {
792 return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
793 }
794
795
796
797 static std::vector<Type_Info> param_types()
798 {
799 return {user_type<T>(), user_type<Class>()};
800 }
801
802 T Class::* m_attr;
803 };
804 }
805
806 namespace exception
807 {
813 class dispatch_error : public std::runtime_error
814 {
815 public:
816 dispatch_error(std::vector<Boxed_Value> t_parameters,
817 std::vector<Const_Proxy_Function> t_functions)
818 : std::runtime_error("Error with function dispatch"), parameters(std::move(t_parameters)), functions(std::move(t_functions))
819 {
820 }
821
822 dispatch_error(std::vector<Boxed_Value> t_parameters,
823 std::vector<Const_Proxy_Function> t_functions,
824 const std::string &t_desc)
825 : std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions))
826 {
827 }
828
829
830 dispatch_error(const dispatch_error &) = default;
831 ~dispatch_error() noexcept override = default;
832
835 };
836 }
837
838 namespace dispatch
839 {
840 namespace detail
841 {
842 template<typename FuncType>
843 bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
844 const Type_Conversions_State &t_conversions)
845 {
846 const std::vector<Type_Info> &types = t_func->get_param_types();
847
848 if (t_func->get_arity() == -1) { return false; }
849
850 assert(plist.size() == types.size() - 1);
851
852 return std::mismatch(plist.begin(), plist.end(),
853 types.begin()+1,
854 [&](const Boxed_Value &bv, const Type_Info &ti) {
855 return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions)
856 || (bv.get_type_info().is_arithmetic() && ti.is_arithmetic());
857 }
858 ) == std::make_pair(plist.end(), types.end());
859 }
860
861 template<typename InItr, typename Funcs>
862 Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
863 const Type_Conversions_State &t_conversions, const Funcs &t_funcs)
864 {
865 InItr matching_func(end);
866
867 while (begin != end)
868 {
869 if (types_match_except_for_arithmetic(begin->second, plist, t_conversions))
870 {
871 if (matching_func == end)
872 {
873 matching_func = begin;
874 } else {
875 // handle const members vs non-const member, which is not really ambiguous
876 const auto &mat_fun_param_types = matching_func->second->get_param_types();
877 const auto &next_fun_param_types = begin->second->get_param_types();
878
879 if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
880 matching_func = begin; // keep the new one, the const/non-const matchup is correct
881 } else if (!plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
882 // keep the old one, it has a better const/non-const matchup
883 } else {
884 // ambiguous function call
885 throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
886 }
887 }
888 }
889
890 ++begin;
891 }
892
893 if (matching_func == end)
894 {
895 // no appropriate function to attempt arithmetic type conversion on
896 throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
897 }
898
899
900 std::vector<Boxed_Value> newplist;
901 newplist.reserve(plist.size());
902
903 const std::vector<Type_Info> &tis = matching_func->second->get_param_types();
904 std::transform(tis.begin() + 1, tis.end(),
905 plist.begin(),
906 std::back_inserter(newplist),
907 [](const Type_Info &ti, const Boxed_Value &param) -> Boxed_Value {
908 if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()
909 && param.get_type_info() != ti) {
910 return Boxed_Number(param).get_as(ti).bv;
911 } else {
912 return param;
913 }
914 }
915 );
916
917 try {
918 return (*(matching_func->second))(newplist, t_conversions);
919 } catch (const exception::bad_boxed_cast &) {
920 //parameter failed to cast
921 } catch (const exception::arity_error &) {
922 //invalid num params
923 } catch (const exception::guard_error &) {
924 //guard failed to allow the function to execute
925 }
926
927 throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
928
929 }
930 }
931
935 template<typename Funcs>
936 Boxed_Value dispatch(const Funcs &funcs,
937 const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions)
938 {
939 std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
940 ordered_funcs.reserve(funcs.size());
941
942 for (const auto &func : funcs)
943 {
944 const auto arity = func->get_arity();
945
946 if (arity == -1)
947 {
948 ordered_funcs.emplace_back(plist.size(), func.get());
949 } else if (arity == static_cast<int>(plist.size())) {
950 size_t numdiffs = 0;
951 for (size_t i = 0; i < plist.size(); ++i)
952 {
953 if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
954 {
955 ++numdiffs;
956 }
957 }
958 ordered_funcs.emplace_back(numdiffs, func.get());
959 }
960 }
961
962
963 for (size_t i = 0; i <= plist.size(); ++i)
964 {
965 for (const auto &func : ordered_funcs )
966 {
967 try {
968 if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions)))
969 {
970 return (*(func.second))(plist, t_conversions);
971 }
972 } catch (const exception::bad_boxed_cast &) {
973 //parameter failed to cast, try again
974 } catch (const exception::arity_error &) {
975 //invalid num params, try again
976 } catch (const exception::guard_error &) {
977 //guard failed to allow the function to execute,
978 //try again
979 }
980 }
981 }
982
983 return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs);
984 }
985 }
986}
987
988
989#endif
P func(int c, EveryApi &ev)
Definition test.cpp:59
int get_arity() const
Returns the arity of the function, -1 if the function takes a variable number of parameters.
Represents any numeric type, generically. Used internally for generic operations between POD values.
Definition boxed_number.hpp:66
A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects.
Definition boxed_value.hpp:28
bool is_const() const noexcept
Definition boxed_value.hpp:235
const Type_Info & get_type_info() const noexcept
Definition boxed_value.hpp:224
Definition type_conversions.hpp:512
Type_Conversions::Conversion_Saves & saves() const
Definition type_conversions.hpp:529
Definition type_conversions.hpp:321
bool converts() const
Definition type_conversions.hpp:379
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
Definition type_conversions.hpp:396
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
Definition type_conversions.hpp:402
Compile time deduced information about a type.
Definition type_info.hpp:34
constexpr bool is_undef() const noexcept
Definition type_info.hpp:90
constexpr bool is_arithmetic() const noexcept
Definition type_info.hpp:89
constexpr bool bare_equal(const Type_Info &ti) const noexcept
Definition type_info.hpp:75
Thrown in the event that an Any cannot be cast to the desired type.
Definition any.hpp:22
std::function< Func > internal_function() const
Definition proxy_functions.hpp:699
Assignable_Proxy_Function_Impl(std::reference_wrapper< std::function< Func > > t_f, std::shared_ptr< std::function< Func > > t_ptr)
Definition proxy_functions.hpp:682
bool compare_types_with_cast(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:689
void assign(const std::shared_ptr< const Proxy_Function_Base > &t_rhs) override
Definition proxy_functions.hpp:704
bool operator==(const Proxy_Function_Base &t_func) const override
Definition proxy_functions.hpp:694
Boxed_Value do_call(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:709
virtual void assign(const std::shared_ptr< const Proxy_Function_Base > &t_rhs)=0
Assignable_Proxy_Function(const std::vector< Type_Info > &t_types)
Definition proxy_functions.hpp:670
Attribute_Access(T Class::*t_attr)
Definition proxy_functions.hpp:726
Boxed_Value do_call(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:757
bool is_attribute_function() const override
Definition proxy_functions.hpp:732
bool operator==(const Proxy_Function_Base &t_func) const override
Definition proxy_functions.hpp:734
bool call_match(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &) const override
Definition proxy_functions.hpp:746
Bound_Function(const Const_Proxy_Function &t_f, const std::vector< Boxed_Value > &t_args)
Definition proxy_functions.hpp:523
std::vector< Boxed_Value > build_param_list(const std::vector< Boxed_Value > &params) const
Definition proxy_functions.hpp:548
Boxed_Value do_call(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:605
bool operator==(const Proxy_Function_Base &t_f) const override
Definition proxy_functions.hpp:531
std::vector< Const_Proxy_Function > get_contained_functions() const override
Definition proxy_functions.hpp:542
static std::vector< Type_Info > build_param_type_info(const Const_Proxy_Function &t_f, const std::vector< Boxed_Value > &t_args)
Definition proxy_functions.hpp:581
bool call_match(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:537
Definition dynamic_object.hpp:44
Dynamic_Proxy_Function_Impl(Callable t_f, int t_arity=-1, std::shared_ptr< AST_Node > t_parsenode=AST_NodePtr(), Param_Types t_param_types=Param_Types(), Proxy_Function t_guard=Proxy_Function())
Definition proxy_functions.hpp:466
Boxed_Value do_call(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:484
Proxy_Function get_guard() const
Definition proxy_functions.hpp:378
bool has_parse_tree() const
Definition proxy_functions.hpp:383
bool call_match(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:372
Dynamic_Proxy_Function(const int t_arity, std::shared_ptr< AST_Node > t_parsenode, Param_Types t_param_types=Param_Types(), Proxy_Function t_guard=Proxy_Function())
Definition proxy_functions.hpp:348
const AST_Node & get_parse_tree() const
Definition proxy_functions.hpp:387
std::pair< bool, bool > call_match_internal(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:416
bool operator==(const Proxy_Function_Base &rhs) const override
Definition proxy_functions.hpp:361
bool test_guard(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:398
Param_Types m_param_types
Definition proxy_functions.hpp:453
Definition proxy_functions.hpp:52
std::vector< Boxed_Value > convert(std::vector< Boxed_Value > vals, const Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:78
Param_Types(std::vector< std::pair< std::string, Type_Info > > t_types)
Definition proxy_functions.hpp:59
void push_front(std::string t_name, Type_Info t_ti)
Definition proxy_functions.hpp:67
Param_Types()
Definition proxy_functions.hpp:54
bool operator==(const Param_Types &t_rhs) const
Definition proxy_functions.hpp:73
const std::vector< std::pair< std::string, Type_Info > > & types() const
Definition proxy_functions.hpp:161
std::pair< bool, bool > match(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:117
Definition proxy_functions.hpp:196
static bool compare_types(const std::vector< Type_Info > &tis, const std::vector< Boxed_Value > &bvs, const Type_Conversions_State &t_conversions)
Definition proxy_functions.hpp:294
virtual bool is_attribute_function() const
Definition proxy_functions.hpp:218
virtual Boxed_Value do_call(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const =0
bool m_has_arithmetic_param
Definition proxy_functions.hpp:312
bool has_arithmetic_param() const
Definition proxy_functions.hpp:220
bool filter(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:232
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:271
Proxy_Function_Base(std::vector< Type_Info > t_types, int t_arity)
Definition proxy_functions.hpp:279
virtual bool call_match(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const =0
std::vector< Type_Info > m_types
Definition proxy_functions.hpp:310
virtual bool operator==(const Proxy_Function_Base &) const =0
int get_arity() const
Definition proxy_functions.hpp:247
Boxed_Value operator()(const std::vector< Boxed_Value > &params, const chaiscript::Type_Conversions_State &t_conversions) const
Definition proxy_functions.hpp:200
int m_arity
Definition proxy_functions.hpp:311
virtual std::vector< std::shared_ptr< const Proxy_Function_Base > > get_contained_functions() const
Definition proxy_functions.hpp:225
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
Definition proxy_functions.hpp:252
const std::vector< Type_Info > & get_param_types() const
Definition proxy_functions.hpp:213
Boxed_Value do_call(const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:657
bool operator==(const Proxy_Function_Base &t_func) const override
Definition proxy_functions.hpp:650
bool compare_types_with_cast(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:645
Proxy_Function_Callable_Impl(Callable f)
Definition proxy_functions.hpp:639
bool call_match(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const override
Definition proxy_functions.hpp:623
virtual bool compare_types_with_cast(const std::vector< Boxed_Value > &vals, const Type_Conversions_State &t_conversions) const =0
Proxy_Function_Impl_Base(const std::vector< Type_Info > &t_types)
Definition proxy_functions.hpp:618
Thrown in the event that a Boxed_Value cannot be cast to the desired type.
Definition bad_boxed_cast.hpp:34
Exception thrown in the case that a method dispatch fails because no matching function was found.
Definition proxy_functions.hpp:814
~dispatch_error() noexcept override=default
std::vector< Const_Proxy_Function > functions
Definition proxy_functions.hpp:834
dispatch_error(const dispatch_error &)=default
std::vector< Boxed_Value > parameters
Definition proxy_functions.hpp:833
dispatch_error(std::vector< Boxed_Value > t_parameters, std::vector< Const_Proxy_Function > t_functions, const std::string &t_desc)
Definition proxy_functions.hpp:822
dispatch_error(std::vector< Boxed_Value > t_parameters, std::vector< Const_Proxy_Function > t_functions)
Definition proxy_functions.hpp:816
Exception thrown if a function's guard fails.
Definition proxy_functions.hpp:327
guard_error() noexcept
Definition proxy_functions.hpp:329
~guard_error() noexcept override=default
guard_error(const guard_error &)=default
d
Definition meshpage.php:3895
iVBORw0KGgoAAAANSUhEUgAAANcAAAB5CAMAAACdtUQZAAAA51BMVEX</div ></div >< div style="padding: 0px 0px; width: 1324px;">< div style="height: 400px; width: 1324px;"></div >< div itemscope itemtype="https: </div><div itemscope itemtype="https:</div >< div itemscope itemtype="https: </div></div><p><div style="padding:0px 0px;width:1324px;"><div></div><div itemscope itemtype="https:< ul >< li >< b > Application name
8AkrcAgqgAs9wqQ0ey2tkAo8gAuuQfeI4hPUH09fXHy8z4+fng4uNKXF/Lz9BzfoAcgpkQMTUAKjAbOT4Qr9AXhJ8Rl7ktMCwTosA...
Definition meshpage.php:1610
n< br > font size
Definition meshpage.php:3536
Classes and functions reserved for internal use. Items in this namespace are not supported.
Definition callable_traits.hpp:14
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector< Boxed_Value > &plist, const Type_Conversions_State &t_conversions, const Funcs &t_funcs)
Definition proxy_functions.hpp:862
Ret call_func(const chaiscript::dispatch::detail::Function_Signature< Ret(Params...)> &, std::index_sequence< I... >, const Callable &f, const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions)
Definition proxy_functions_detail.hpp:97
bool compare_types_cast(Ret(*)(Params...), const std::vector< Boxed_Value > &params, const Type_Conversions_State &t_conversions)
Definition proxy_functions_detail.hpp:80
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector< Boxed_Value > &plist, const Type_Conversions_State &t_conversions)
Definition proxy_functions.hpp:843
Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use t...
Definition callable_traits.hpp:13
Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg &&... a)
Definition proxy_functions.hpp:504
Boxed_Value dispatch(const Funcs &funcs, const std::vector< Boxed_Value > &plist, const Type_Conversions_State &t_conversions)
Definition proxy_functions.hpp:936
std::function< FunctionType > functor(const std::vector< Const_Proxy_Function > &funcs, const Type_Conversions_State *t_conversions)
Definition function_call.hpp:42
Classes which may be thrown during error cases when ChaiScript is executing.
Definition bad_boxed_cast.hpp:27
Namespace chaiscript contains every API call that the average user will be concerned with.
std::shared_ptr< dispatch::Proxy_Function_Base > Proxy_Function
Common typedef used for passing of any registered function in ChaiScript.
Definition proxy_functions.hpp:317
std::shared_ptr< const dispatch::Proxy_Function_Base > Const_Proxy_Function
Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functi...
Definition proxy_functions.hpp:321
constexpr Type_Info user_type(const T &)
Creates a Type_Info object representing the type passed in.
Definition type_info.hpp:221
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:76
std::shared_ptr< B > make_shared(Arg &&... arg)
Definition chaiscript_defines.hpp:87
@ Arg
Definition chaiscript_common.hpp:69
@ Class
Definition chaiscript_common.hpp:69
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:44
STL namespace.
double f(const std::string &, double, bool) noexcept
Definition profile_cpp_calls_2.cpp:4
Definition parser.cc:9
Definition GameApi.h:42
Struct that doubles as both a parser ast_node and an AST node.
Definition chaiscript_common.hpp:497
static constexpr Type_Info get()
Definition type_info.hpp:138
Definition proxy_functions.hpp:513
Definition callable_traits.hpp:78
static Boxed_Value handle(T r)
Definition handle_return.hpp:40
Definition proxy_functions_detail.hpp:42