proxy_functions.hpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. // This file is distributed under the BSD License.
  2. // See "license.txt" for details.
  3. // Copyright 2009-2012, Jonathan Turner ([email protected])
  4. // Copyright 2009-2017, Jason Turner ([email protected])
  5. // http://www.chaiscript.com
  6. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
  7. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
  8. #ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_
  9. #define CHAISCRIPT_PROXY_FUNCTIONS_HPP_
  10. #include <cassert>
  11. #include <functional>
  12. #include <memory>
  13. #include <stdexcept>
  14. #include <string>
  15. #include <type_traits>
  16. #include <vector>
  17. #include <iterator>
  18. #include "../chaiscript_defines.hpp"
  19. #include "boxed_cast.hpp"
  20. #include "boxed_value.hpp"
  21. #include "proxy_functions_detail.hpp"
  22. #include "type_info.hpp"
  23. #include "dynamic_object.hpp"
  24. namespace chaiscript {
  25. class Type_Conversions;
  26. namespace exception {
  27. class bad_boxed_cast;
  28. struct arity_error;
  29. } // namespace exception
  30. } // namespace chaiscript
  31. namespace chaiscript
  32. {
  33. class Boxed_Number;
  34. struct AST_Node;
  35. typedef std::unique_ptr<AST_Node> AST_NodePtr;
  36. namespace dispatch
  37. {
  38. template<typename FunctionType>
  39. std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions_State *t_conversions);
  40. class Param_Types
  41. {
  42. public:
  43. Param_Types()
  44. : m_has_types(false),
  45. m_doti(user_type<Dynamic_Object>())
  46. {}
  47. explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
  48. : m_types(std::move(t_types)),
  49. m_has_types(false),
  50. m_doti(user_type<Dynamic_Object>())
  51. {
  52. update_has_types();
  53. }
  54. void push_front(std::string t_name, Type_Info t_ti)
  55. {
  56. m_types.emplace(m_types.begin(), std::move(t_name), t_ti);
  57. update_has_types();
  58. }
  59. bool operator==(const Param_Types &t_rhs) const
  60. {
  61. return m_types == t_rhs.m_types;
  62. }
  63. std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const
  64. {
  65. for (size_t i = 0; i < vals.size(); ++i)
  66. {
  67. const auto &name = m_types[i].first;
  68. if (!name.empty()) {
  69. const auto &bv = vals[i];
  70. if (!bv.get_type_info().bare_equal(m_doti))
  71. {
  72. const auto &ti = m_types[i].second;
  73. if (!ti.is_undef())
  74. {
  75. if (!bv.get_type_info().bare_equal(ti)) {
  76. if (t_conversions->converts(ti, bv.get_type_info())) {
  77. try {
  78. // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
  79. // either way, we are not responsible if it doesn't work
  80. vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
  81. } catch (...) {
  82. try {
  83. // try going the other way
  84. vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]);
  85. } catch (const chaiscript::detail::exception::bad_any_cast &) {
  86. throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info());
  87. }
  88. }
  89. }
  90. }
  91. }
  92. }
  93. }
  94. }
  95. return vals;
  96. }
  97. // first result: is a match
  98. // second result: needs conversions
  99. std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
  100. {
  101. bool needs_conversion = false;
  102. if (!m_has_types) { return std::make_pair(true, needs_conversion); }
  103. if (vals.size() != m_types.size()) { return std::make_pair(false, needs_conversion); }
  104. for (size_t i = 0; i < vals.size(); ++i)
  105. {
  106. const auto &name = m_types[i].first;
  107. if (!name.empty()) {
  108. const auto &bv = vals[i];
  109. if (bv.get_type_info().bare_equal(m_doti))
  110. {
  111. try {
  112. const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
  113. if (!(name == "Dynamic_Object" || d.get_type_name() == name)) {
  114. return std::make_pair(false, false);
  115. }
  116. } catch (const std::bad_cast &) {
  117. return std::make_pair(false, false);
  118. }
  119. } else {
  120. const auto &ti = m_types[i].second;
  121. if (!ti.is_undef())
  122. {
  123. if (!bv.get_type_info().bare_equal(ti)) {
  124. if (!t_conversions->converts(ti, bv.get_type_info())) {
  125. return std::make_pair(false, false);
  126. } else {
  127. needs_conversion = true;
  128. }
  129. }
  130. } else {
  131. return std::make_pair(false, false);
  132. }
  133. }
  134. }
  135. }
  136. return std::make_pair(true, needs_conversion);
  137. }
  138. const std::vector<std::pair<std::string, Type_Info>> &types() const
  139. {
  140. return m_types;
  141. }
  142. private:
  143. void update_has_types()
  144. {
  145. for (const auto &type : m_types)
  146. {
  147. if (!type.first.empty())
  148. {
  149. m_has_types = true;
  150. return;
  151. }
  152. }
  153. m_has_types = false;
  154. }
  155. std::vector<std::pair<std::string, Type_Info>> m_types;
  156. bool m_has_types;
  157. Type_Info m_doti;
  158. };
  159. /**
  160. * Pure virtual base class for all Proxy_Function implementations
  161. * Proxy_Functions are a type erasure of type safe C++
  162. * function calls. At runtime parameter types are expected to be
  163. * tested against passed in types.
  164. * Dispatch_Engine only knows how to work with Proxy_Function, no other
  165. * function classes.
  166. */
  167. class Proxy_Function_Base
  168. {
  169. public:
  170. virtual ~Proxy_Function_Base() = default;
  171. Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions_State &t_conversions) const
  172. {
  173. if (m_arity < 0 || size_t(m_arity) == params.size()) {
  174. return do_call(params, t_conversions);
  175. } else {
  176. throw exception::arity_error(static_cast<int>(params.size()), m_arity);
  177. }
  178. }
  179. /// Returns a vector containing all of the types of the parameters the function returns/takes
  180. /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned
  181. /// value contains exactly 1 Type_Info object: the return type
  182. /// \returns the types of all parameters.
  183. const std::vector<Type_Info> &get_param_types() const { return m_types; }
  184. virtual bool operator==(const Proxy_Function_Base &) const = 0;
  185. virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
  186. virtual bool is_attribute_function() const { return false; }
  187. bool has_arithmetic_param() const
  188. {
  189. return m_has_arithmetic_param;
  190. }
  191. virtual std::vector<std::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
  192. {
  193. return std::vector<std::shared_ptr<const Proxy_Function_Base> >();
  194. }
  195. //! Return true if the function is a possible match
  196. //! to the passed in values
  197. bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
  198. {
  199. assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
  200. if (m_arity < 0)
  201. {
  202. return true;
  203. } else if (m_arity > 1) {
  204. return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
  205. } else {
  206. return compare_type_to_param(m_types[1], vals[0], t_conversions);
  207. }
  208. }
  209. /// \returns the number of arguments the function takes or -1 if it is variadic
  210. int get_arity() const
  211. {
  212. return m_arity;
  213. }
  214. static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
  215. {
  216. if (ti.is_undef()
  217. || ti.bare_equal(user_type<Boxed_Value>())
  218. || (!bv.get_type_info().is_undef()
  219. && ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
  220. || ti.bare_equal(bv.get_type_info())
  221. || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
  222. || t_conversions->converts(ti, bv.get_type_info())
  223. )
  224. )
  225. )
  226. {
  227. return true;
  228. } else {
  229. return false;
  230. }
  231. }
  232. virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const
  233. {
  234. return compare_type_to_param(m_types[1], bv, t_conversions);
  235. }
  236. protected:
  237. virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const = 0;
  238. Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
  239. : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
  240. {
  241. for (size_t i = 1; i < m_types.size(); ++i)
  242. {
  243. if (m_types[i].is_arithmetic())
  244. {
  245. m_has_arithmetic_param = true;
  246. return;
  247. }
  248. }
  249. }
  250. static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs,
  251. const Type_Conversions_State &t_conversions)
  252. {
  253. if (tis.size() - 1 != bvs.size())
  254. {
  255. return false;
  256. } else {
  257. const size_t size = bvs.size();
  258. for (size_t i = 0; i < size; ++i)
  259. {
  260. if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; }
  261. }
  262. }
  263. return true;
  264. }
  265. std::vector<Type_Info> m_types;
  266. int m_arity;
  267. bool m_has_arithmetic_param;
  268. };
  269. }
  270. /// \brief Common typedef used for passing of any registered function in ChaiScript
  271. typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
  272. /// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions
  273. /// are handled internally.
  274. typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
  275. namespace exception
  276. {
  277. /// \brief Exception thrown if a function's guard fails
  278. class guard_error : public std::runtime_error
  279. {
  280. public:
  281. guard_error() noexcept
  282. : std::runtime_error("Guard evaluation failed")
  283. { }
  284. guard_error(const guard_error &) = default;
  285. ~guard_error() noexcept override = default;
  286. };
  287. }
  288. namespace dispatch
  289. {
  290. /**
  291. * A Proxy_Function implementation that is not type safe, the called function
  292. * is expecting a vector<Boxed_Value> that it works with how it chooses.
  293. */
  294. class Dynamic_Proxy_Function : public Proxy_Function_Base
  295. {
  296. public:
  297. Dynamic_Proxy_Function(
  298. const int t_arity,
  299. std::shared_ptr<AST_Node> t_parsenode,
  300. Param_Types t_param_types = Param_Types(),
  301. Proxy_Function t_guard = Proxy_Function())
  302. : Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
  303. m_param_types(std::move(t_param_types)),
  304. m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
  305. {
  306. // assert(t_parsenode);
  307. }
  308. bool operator==(const Proxy_Function_Base &rhs) const override
  309. {
  310. const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
  311. return this == &rhs
  312. || ((prhs != nullptr)
  313. && this->m_arity == prhs->m_arity
  314. && !this->m_guard && !prhs->m_guard
  315. && this->m_param_types == prhs->m_param_types);
  316. }
  317. bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
  318. {
  319. return call_match_internal(vals, t_conversions).first;
  320. }
  321. Proxy_Function get_guard() const
  322. {
  323. return m_guard;
  324. }
  325. bool has_parse_tree() const {
  326. return static_cast<bool>(m_parsenode);
  327. }
  328. const AST_Node &get_parse_tree() const
  329. {
  330. if (m_parsenode) {
  331. return *m_parsenode;
  332. } else {
  333. throw std::runtime_error("Dynamic_Proxy_Function does not have parse_tree");
  334. }
  335. }
  336. protected:
  337. bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const
  338. {
  339. if (m_guard)
  340. {
  341. try {
  342. return boxed_cast<bool>((*m_guard)(params, t_conversions));
  343. } catch (const exception::arity_error &) {
  344. return false;
  345. } catch (const exception::bad_boxed_cast &) {
  346. return false;
  347. }
  348. } else {
  349. return true;
  350. }
  351. }
  352. // first result: is a match
  353. // second result: needs conversions
  354. std::pair<bool, bool> call_match_internal(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
  355. {
  356. const auto comparison_result = [&](){
  357. if (m_arity < 0) {
  358. return std::make_pair(true, false);
  359. } else if (vals.size() == size_t(m_arity)) {
  360. return m_param_types.match(vals, t_conversions);
  361. } else {
  362. return std::make_pair(false, false);
  363. }
  364. }();
  365. return std::make_pair(
  366. comparison_result.first && test_guard(vals, t_conversions),
  367. comparison_result.second
  368. );
  369. }
  370. private:
  371. static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
  372. {
  373. // For the return type
  374. std::vector<Type_Info> types{chaiscript::detail::Get_Type_Info<Boxed_Value>::get()};
  375. for (const auto &t : t_types.types())
  376. {
  377. if (t.second.is_undef()) {
  378. types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
  379. } else {
  380. types.push_back(t.second);
  381. }
  382. }
  383. return types;
  384. }
  385. protected:
  386. Param_Types m_param_types;
  387. private:
  388. Proxy_Function m_guard;
  389. std::shared_ptr<AST_Node> m_parsenode;
  390. };
  391. template<typename Callable>
  392. class Dynamic_Proxy_Function_Impl final : public Dynamic_Proxy_Function
  393. {
  394. public:
  395. Dynamic_Proxy_Function_Impl(
  396. Callable t_f,
  397. int t_arity=-1,
  398. std::shared_ptr<AST_Node> t_parsenode = AST_NodePtr(),
  399. Param_Types t_param_types = Param_Types(),
  400. Proxy_Function t_guard = Proxy_Function())
  401. : Dynamic_Proxy_Function(
  402. t_arity,
  403. std::move(t_parsenode),
  404. std::move(t_param_types),
  405. std::move(t_guard)
  406. ),
  407. m_f(std::move(t_f))
  408. {
  409. }
  410. protected:
  411. Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
  412. {
  413. const auto match_results = call_match_internal(params, t_conversions);
  414. if (match_results.first)
  415. {
  416. if (match_results.second) {
  417. return m_f(m_param_types.convert(params, t_conversions));
  418. } else {
  419. return m_f(params);
  420. }
  421. } else {
  422. throw exception::guard_error();
  423. }
  424. }
  425. private:
  426. Callable m_f;
  427. };
  428. template<typename Callable, typename ... Arg>
  429. Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg&& ... a)
  430. {
  431. return chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function_Impl<Callable>>(
  432. std::forward<Callable>(c), std::forward<Arg>(a)...);
  433. }
  434. /// An object used by Bound_Function to represent "_" parameters
  435. /// of a binding. This allows for unbound parameters during bind.
  436. struct Placeholder_Object
  437. {
  438. };
  439. /// An implementation of Proxy_Function that takes a Proxy_Function
  440. /// and substitutes bound parameters into the parameter list
  441. /// at runtime, when call() is executed.
  442. /// it is used for bind(function, param1, _, param2) style calls
  443. class Bound_Function final : public Proxy_Function_Base
  444. {
  445. public:
  446. Bound_Function(const Const_Proxy_Function &t_f,
  447. const std::vector<Boxed_Value> &t_args)
  448. : 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)),
  449. m_f(t_f), m_args(t_args)
  450. {
  451. assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
  452. }
  453. bool operator==(const Proxy_Function_Base &t_f) const override
  454. {
  455. return &t_f == this;
  456. }
  457. bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
  458. {
  459. return m_f->call_match(build_param_list(vals), t_conversions);
  460. }
  461. std::vector<Const_Proxy_Function> get_contained_functions() const override
  462. {
  463. return std::vector<Const_Proxy_Function>{m_f};
  464. }
  465. std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const
  466. {
  467. auto parg = params.begin();
  468. auto barg = m_args.begin();
  469. std::vector<Boxed_Value> args;
  470. while (!(parg == params.end() && barg == m_args.end()))
  471. {
  472. while (barg != m_args.end()
  473. && !(barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get()))
  474. {
  475. args.push_back(*barg);
  476. ++barg;
  477. }
  478. if (parg != params.end())
  479. {
  480. args.push_back(*parg);
  481. ++parg;
  482. }
  483. if (barg != m_args.end()
  484. && barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get())
  485. {
  486. ++barg;
  487. }
  488. }
  489. return args;
  490. }
  491. protected:
  492. static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
  493. const std::vector<Boxed_Value> &t_args)
  494. {
  495. assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast<int>(t_args.size()));
  496. if (t_f->get_arity() < 0) { return std::vector<Type_Info>(); }
  497. const auto types = t_f->get_param_types();
  498. assert(types.size() == t_args.size() + 1);
  499. // this analysis warning is invalid in MSVC12 and doesn't exist in MSVC14
  500. std::vector<Type_Info> retval{types[0]};
  501. for (size_t i = 0; i < types.size() - 1; ++i)
  502. {
  503. if (t_args[i].get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get())
  504. {
  505. retval.push_back(types[i+1]);
  506. }
  507. }
  508. return retval;
  509. }
  510. Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
  511. {
  512. return (*m_f)(build_param_list(params), t_conversions);
  513. }
  514. private:
  515. Const_Proxy_Function m_f;
  516. std::vector<Boxed_Value> m_args;
  517. };
  518. class Proxy_Function_Impl_Base : public Proxy_Function_Base
  519. {
  520. public:
  521. explicit Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
  522. : Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
  523. {
  524. }
  525. bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
  526. {
  527. return static_cast<int>(vals.size()) == get_arity()
  528. && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
  529. }
  530. virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
  531. };
  532. /// For any callable object
  533. template<typename Func, typename Callable>
  534. class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base
  535. {
  536. public:
  537. explicit Proxy_Function_Callable_Impl(Callable f)
  538. : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
  539. m_f(std::move(f))
  540. {
  541. }
  542. bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
  543. {
  544. return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
  545. }
  546. bool operator==(const Proxy_Function_Base &t_func) const override
  547. {
  548. return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr;
  549. }
  550. protected:
  551. Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
  552. {
  553. return detail::call_func(detail::Function_Signature<Func>(), m_f, params, t_conversions);
  554. }
  555. private:
  556. Callable m_f;
  557. };
  558. class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
  559. {
  560. public:
  561. explicit Assignable_Proxy_Function(const std::vector<Type_Info> &t_types)
  562. : Proxy_Function_Impl_Base(t_types)
  563. {
  564. }
  565. virtual void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) = 0;
  566. };
  567. template<typename Func>
  568. class Assignable_Proxy_Function_Impl final : public Assignable_Proxy_Function
  569. {
  570. public:
  571. Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr)
  572. : Assignable_Proxy_Function(detail::build_param_type_list(static_cast<Func *>(nullptr))),
  573. m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr))
  574. {
  575. assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
  576. }
  577. bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
  578. {
  579. return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
  580. }
  581. bool operator==(const Proxy_Function_Base &t_func) const override
  582. {
  583. return dynamic_cast<const Assignable_Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
  584. }
  585. std::function<Func> internal_function() const
  586. {
  587. return m_f.get();
  588. }
  589. void assign(const std::shared_ptr<const Proxy_Function_Base> &t_rhs) override {
  590. m_f.get() = dispatch::functor<Func>(t_rhs, nullptr);
  591. }
  592. protected:
  593. Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
  594. {
  595. return detail::call_func(detail::Function_Signature<Func>(), m_f.get(), params, t_conversions);
  596. }
  597. private:
  598. std::reference_wrapper<std::function<Func>> m_f;
  599. std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
  600. };
  601. /// Attribute getter Proxy_Function implementation
  602. template<typename T, typename Class>
  603. class Attribute_Access final : public Proxy_Function_Base
  604. {
  605. public:
  606. explicit Attribute_Access(T Class::* t_attr)
  607. : Proxy_Function_Base(param_types(), 1),
  608. m_attr(t_attr)
  609. {
  610. }
  611. bool is_attribute_function() const override { return true; }
  612. bool operator==(const Proxy_Function_Base &t_func) const override
  613. {
  614. const Attribute_Access<T, Class> * aa
  615. = dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
  616. if (aa) {
  617. return m_attr == aa->m_attr;
  618. } else {
  619. return false;
  620. }
  621. }
  622. bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const override
  623. {
  624. if (vals.size() != 1)
  625. {
  626. return false;
  627. }
  628. return vals[0].get_type_info().bare_equal(user_type<Class>());
  629. }
  630. protected:
  631. Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
  632. {
  633. const Boxed_Value &bv = params[0];
  634. if (bv.is_const())
  635. {
  636. const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
  637. return do_call_impl<T>(o);
  638. } else {
  639. Class *o = boxed_cast<Class *>(bv, &t_conversions);
  640. return do_call_impl<T>(o);
  641. }
  642. }
  643. private:
  644. template<typename Type>
  645. auto do_call_impl(Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
  646. {
  647. return detail::Handle_Return<Type>::handle(o->*m_attr);
  648. }
  649. template<typename Type>
  650. auto do_call_impl(const Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
  651. {
  652. return detail::Handle_Return<const Type>::handle(o->*m_attr);
  653. }
  654. template<typename Type>
  655. auto do_call_impl(Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
  656. {
  657. return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
  658. }
  659. template<typename Type>
  660. auto do_call_impl(const Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
  661. {
  662. return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
  663. }
  664. static std::vector<Type_Info> param_types()
  665. {
  666. return {user_type<T>(), user_type<Class>()};
  667. }
  668. T Class::* m_attr;
  669. };
  670. }
  671. namespace exception
  672. {
  673. /// \brief Exception thrown in the case that a method dispatch fails
  674. /// because no matching function was found
  675. ///
  676. /// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast
  677. /// exception
  678. class dispatch_error : public std::runtime_error
  679. {
  680. public:
  681. dispatch_error(std::vector<Boxed_Value> t_parameters,
  682. std::vector<Const_Proxy_Function> t_functions)
  683. : std::runtime_error("Error with function dispatch"), parameters(std::move(t_parameters)), functions(std::move(t_functions))
  684. {
  685. }
  686. dispatch_error(std::vector<Boxed_Value> t_parameters,
  687. std::vector<Const_Proxy_Function> t_functions,
  688. const std::string &t_desc)
  689. : std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions))
  690. {
  691. }
  692. dispatch_error(const dispatch_error &) = default;
  693. ~dispatch_error() noexcept override = default;
  694. std::vector<Boxed_Value> parameters;
  695. std::vector<Const_Proxy_Function> functions;
  696. };
  697. }
  698. namespace dispatch
  699. {
  700. namespace detail
  701. {
  702. template<typename FuncType>
  703. bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
  704. const Type_Conversions_State &t_conversions)
  705. {
  706. const std::vector<Type_Info> &types = t_func->get_param_types();
  707. if (t_func->get_arity() == -1) { return false; }
  708. assert(plist.size() == types.size() - 1);
  709. return std::mismatch(plist.begin(), plist.end(),
  710. types.begin()+1,
  711. [&](const Boxed_Value &bv, const Type_Info &ti) {
  712. return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions)
  713. || (bv.get_type_info().is_arithmetic() && ti.is_arithmetic());
  714. }
  715. ) == std::make_pair(plist.end(), types.end());
  716. }
  717. template<typename InItr, typename Funcs>
  718. Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
  719. const Type_Conversions_State &t_conversions, const Funcs &t_funcs)
  720. {
  721. InItr matching_func(end);
  722. while (begin != end)
  723. {
  724. if (types_match_except_for_arithmetic(begin->second, plist, t_conversions))
  725. {
  726. if (matching_func == end)
  727. {
  728. matching_func = begin;
  729. } else {
  730. // handle const members vs non-const member, which is not really ambiguous
  731. const auto &mat_fun_param_types = matching_func->second->get_param_types();
  732. const auto &next_fun_param_types = begin->second->get_param_types();
  733. if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
  734. matching_func = begin; // keep the new one, the const/non-const matchup is correct
  735. } else if (!plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
  736. // keep the old one, it has a better const/non-const matchup
  737. } else {
  738. // ambiguous function call
  739. throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
  740. }
  741. }
  742. }
  743. ++begin;
  744. }
  745. if (matching_func == end)
  746. {
  747. // no appropriate function to attempt arithmetic type conversion on
  748. throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
  749. }
  750. std::vector<Boxed_Value> newplist;
  751. 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(),
  754. plist.begin(),
  755. std::back_inserter(newplist),
  756. [](const Type_Info &ti, const Boxed_Value &param) -> Boxed_Value {
  757. if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()
  758. && param.get_type_info() != ti) {
  759. return Boxed_Number(param).get_as(ti).bv;
  760. } else {
  761. return param;
  762. }
  763. }
  764. );
  765. try {
  766. return (*(matching_func->second))(newplist, t_conversions);
  767. } catch (const exception::bad_boxed_cast &) {
  768. //parameter failed to cast
  769. } catch (const exception::arity_error &) {
  770. //invalid num params
  771. } catch (const exception::guard_error &) {
  772. //guard failed to allow the function to execute
  773. }
  774. throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
  775. }
  776. }
  777. /// Take a vector of functions and a vector of parameters. Attempt to execute
  778. /// each function against the set of parameters, in order, until a matching
  779. /// function is found or throw dispatch_error if no matching function is found
  780. template<typename Funcs>
  781. Boxed_Value dispatch(const Funcs &funcs,
  782. const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions)
  783. {
  784. std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
  785. ordered_funcs.reserve(funcs.size());
  786. for (const auto &func : funcs)
  787. {
  788. const auto arity = func->get_arity();
  789. if (arity == -1)
  790. {
  791. ordered_funcs.emplace_back(plist.size(), func.get());
  792. } else if (arity == static_cast<int>(plist.size())) {
  793. size_t numdiffs = 0;
  794. for (size_t i = 0; i < plist.size(); ++i)
  795. {
  796. if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
  797. {
  798. ++numdiffs;
  799. }
  800. }
  801. ordered_funcs.emplace_back(numdiffs, func.get());
  802. }
  803. }
  804. for (size_t i = 0; i <= plist.size(); ++i)
  805. {
  806. for (const auto &func : ordered_funcs )
  807. {
  808. try {
  809. if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions)))
  810. {
  811. return (*(func.second))(plist, t_conversions);
  812. }
  813. } catch (const exception::bad_boxed_cast &) {
  814. //parameter failed to cast, try again
  815. } catch (const exception::arity_error &) {
  816. //invalid num params, try again
  817. } catch (const exception::guard_error &) {
  818. //guard failed to allow the function to execute,
  819. //try again
  820. }
  821. }
  822. }
  823. return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs);
  824. }
  825. }
  826. }
  827. #endif