chaiscript_eval.hpp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  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_EVAL_HPP_
  9. #define CHAISCRIPT_EVAL_HPP_
  10. #include <exception>
  11. #include <functional>
  12. #include <limits>
  13. #include <map>
  14. #include <memory>
  15. #include <ostream>
  16. #include <stdexcept>
  17. #include <string>
  18. #include <vector>
  19. #include "../chaiscript_defines.hpp"
  20. #include "../dispatchkit/boxed_cast.hpp"
  21. #include "../dispatchkit/boxed_number.hpp"
  22. #include "../dispatchkit/boxed_value.hpp"
  23. #include "../dispatchkit/dispatchkit.hpp"
  24. #include "../dispatchkit/dynamic_object_detail.hpp"
  25. #include "../dispatchkit/proxy_functions.hpp"
  26. #include "../dispatchkit/proxy_functions_detail.hpp"
  27. #include "../dispatchkit/register_function.hpp"
  28. #include "../dispatchkit/type_info.hpp"
  29. #include "chaiscript_algebraic.hpp"
  30. #include "chaiscript_common.hpp"
  31. namespace chaiscript {
  32. namespace exception {
  33. class bad_boxed_cast;
  34. } // namespace exception
  35. } // namespace chaiscript
  36. namespace chaiscript
  37. {
  38. /// \brief Classes and functions that are part of the runtime eval system
  39. namespace eval
  40. {
  41. template<typename T> struct AST_Node_Impl;
  42. template<typename T> using AST_Node_Impl_Ptr = typename std::unique_ptr<AST_Node_Impl<T>>;
  43. namespace detail
  44. {
  45. /// Helper function that will set up the scope around a function call, including handling the named function parameters
  46. template<typename T>
  47. static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl<T> &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
  48. chaiscript::detail::Dispatch_State state(t_ss);
  49. const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
  50. auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
  51. if (!stack.empty() && stack.back().first == "__this") {
  52. return &stack.back().second;
  53. } else if (!t_vals.empty()) {
  54. return &t_vals[0];
  55. } else {
  56. return nullptr;
  57. }
  58. }();
  59. chaiscript::eval::detail::Stack_Push_Pop tpp(state);
  60. if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); }
  61. if (t_locals) {
  62. for (const auto &local : *t_locals) {
  63. state.add_object(local.first, local.second);
  64. }
  65. }
  66. for (size_t i = 0; i < t_param_names.size(); ++i) {
  67. if (t_param_names[i] != "this") {
  68. state.add_object(t_param_names[i], t_vals[i]);
  69. }
  70. }
  71. try {
  72. return t_node.eval(state);
  73. } catch (detail::Return_Value &rv) {
  74. return std::move(rv.retval);
  75. }
  76. }
  77. }
  78. template<typename T>
  79. struct AST_Node_Impl : AST_Node
  80. {
  81. AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc,
  82. std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>())
  83. : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)),
  84. children(std::move(t_children))
  85. {
  86. }
  87. static bool get_scoped_bool_condition(const AST_Node_Impl<T> &node, const chaiscript::detail::Dispatch_State &t_ss) {
  88. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  89. return get_bool_condition(node.eval(t_ss), t_ss);
  90. }
  91. std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
  92. std::vector<std::reference_wrapper<AST_Node>> retval;
  93. retval.reserve(children.size());
  94. for (auto &&child : children) {
  95. retval.emplace_back(*child);
  96. }
  97. return retval;
  98. }
  99. Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final
  100. {
  101. try {
  102. T::trace(t_e, this);
  103. return eval_internal(t_e);
  104. } catch (exception::eval_error &ee) {
  105. ee.call_stack.push_back(*this);
  106. throw;
  107. }
  108. }
  109. std::vector<AST_Node_Impl_Ptr<T>> children;
  110. protected:
  111. virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
  112. {
  113. throw std::runtime_error("Undispatched ast_node (internal error)");
  114. }
  115. };
  116. template<typename T>
  117. struct Compiled_AST_Node : AST_Node_Impl<T> {
  118. Compiled_AST_Node(AST_Node_Impl_Ptr<T> t_original_node, std::vector<AST_Node_Impl_Ptr<T>> t_children,
  119. std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) :
  120. AST_Node_Impl<T>(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)),
  121. m_func(std::move(t_func)),
  122. m_original_node(std::move(t_original_node))
  123. { }
  124. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  125. return m_func(this->children, t_ss);
  126. }
  127. std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func;
  128. AST_Node_Impl_Ptr<T> m_original_node;
  129. };
  130. template<typename T>
  131. struct Fold_Right_Binary_Operator_AST_Node : AST_Node_Impl<T> {
  132. Fold_Right_Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children, Boxed_Value t_rhs) :
  133. AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),
  134. m_oper(Operators::to_operator(t_oper)),
  135. m_rhs(std::move(t_rhs))
  136. { }
  137. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  138. return do_oper(t_ss, this->text, this->children[0]->eval(t_ss));
  139. }
  140. protected:
  141. Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
  142. const std::string &t_oper_string, const Boxed_Value &t_lhs) const
  143. {
  144. try {
  145. if (t_lhs.get_type_info().is_arithmetic())
  146. {
  147. // If it's an arithmetic operation we want to short circuit dispatch
  148. try{
  149. return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs);
  150. } catch (const chaiscript::exception::arithmetic_error &) {
  151. throw;
  152. } catch (...) {
  153. throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
  154. }
  155. } else {
  156. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  157. fpp.save_params({t_lhs, m_rhs});
  158. return t_ss->call_function(t_oper_string, m_loc, {t_lhs, m_rhs}, t_ss.conversions());
  159. }
  160. }
  161. catch(const exception::dispatch_error &e){
  162. throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
  163. }
  164. }
  165. private:
  166. Operators::Opers m_oper;
  167. Boxed_Value m_rhs;
  168. mutable std::atomic_uint_fast32_t m_loc = {0};
  169. };
  170. template<typename T>
  171. struct Binary_Operator_AST_Node : AST_Node_Impl<T> {
  172. Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  173. AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),
  174. m_oper(Operators::to_operator(t_oper))
  175. { }
  176. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  177. auto lhs = this->children[0]->eval(t_ss);
  178. auto rhs = this->children[1]->eval(t_ss);
  179. return do_oper(t_ss, m_oper, this->text, lhs, rhs);
  180. }
  181. protected:
  182. Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
  183. Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const
  184. {
  185. try {
  186. if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic())
  187. {
  188. // If it's an arithmetic operation we want to short circuit dispatch
  189. try{
  190. return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
  191. } catch (const chaiscript::exception::arithmetic_error &) {
  192. throw;
  193. } catch (...) {
  194. throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
  195. }
  196. } else {
  197. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  198. fpp.save_params({t_lhs, t_rhs});
  199. return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions());
  200. }
  201. }
  202. catch(const exception::dispatch_error &e){
  203. throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
  204. }
  205. }
  206. private:
  207. Operators::Opers m_oper;
  208. mutable std::atomic_uint_fast32_t m_loc = {0};
  209. };
  210. template<typename T>
  211. struct Constant_AST_Node final : AST_Node_Impl<T> {
  212. Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value)
  213. : AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)),
  214. m_value(std::move(t_value))
  215. {
  216. }
  217. explicit Constant_AST_Node(Boxed_Value t_value)
  218. : AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()),
  219. m_value(std::move(t_value))
  220. {
  221. }
  222. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
  223. return m_value;
  224. }
  225. Boxed_Value m_value;
  226. };
  227. template<typename T>
  228. struct Id_AST_Node final : AST_Node_Impl<T> {
  229. Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
  230. AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc))
  231. { }
  232. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  233. try {
  234. return t_ss.get_object(this->text, m_loc);
  235. }
  236. catch (std::exception &) {
  237. throw exception::eval_error("Can not find object: " + this->text);
  238. }
  239. }
  240. private:
  241. mutable std::atomic_uint_fast32_t m_loc = {0};
  242. };
  243. template<typename T>
  244. struct Fun_Call_AST_Node : AST_Node_Impl<T> {
  245. Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  246. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) {
  247. assert(!this->children.empty());
  248. }
  249. template<bool Save_Params>
  250. Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
  251. {
  252. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  253. std::vector<Boxed_Value> params;
  254. params.reserve(this->children[1]->children.size());
  255. for (const auto &child : this->children[1]->children) {
  256. params.push_back(child->eval(t_ss));
  257. }
  258. if (Save_Params) {
  259. fpp.save_params(params);
  260. }
  261. Boxed_Value fn(this->children[0]->eval(t_ss));
  262. try {
  263. return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(params, t_ss.conversions());
  264. }
  265. catch(const exception::dispatch_error &e){
  266. throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
  267. }
  268. catch(const exception::bad_boxed_cast &){
  269. try {
  270. Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
  271. // handle the case where there is only 1 function to try to call and dispatch fails on it
  272. throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
  273. } catch (const exception::bad_boxed_cast &) {
  274. throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
  275. }
  276. }
  277. catch(const exception::arity_error &e){
  278. throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
  279. }
  280. catch(const exception::guard_error &e){
  281. throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
  282. }
  283. catch(detail::Return_Value &rv) {
  284. return rv.retval;
  285. }
  286. }
  287. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
  288. {
  289. return do_eval_internal<true>(t_ss);
  290. }
  291. };
  292. template<typename T>
  293. struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node<T> {
  294. Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  295. Fun_Call_AST_Node<T>(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { }
  296. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
  297. {
  298. return this->template do_eval_internal<false>(t_ss);
  299. }
  300. };
  301. template<typename T>
  302. struct Arg_AST_Node final : AST_Node_Impl<T> {
  303. Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  304. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
  305. };
  306. template<typename T>
  307. struct Arg_List_AST_Node final : AST_Node_Impl<T> {
  308. Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  309. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
  310. static std::string get_arg_name(const AST_Node_Impl<T> &t_node) {
  311. if (t_node.children.empty())
  312. {
  313. return t_node.text;
  314. } else if (t_node.children.size() == 1) {
  315. return t_node.children[0]->text;
  316. } else {
  317. return t_node.children[1]->text;
  318. }
  319. }
  320. static std::vector<std::string> get_arg_names(const AST_Node_Impl<T> &t_node) {
  321. std::vector<std::string> retval;
  322. for (const auto &node : t_node.children)
  323. {
  324. retval.push_back(get_arg_name(*node));
  325. }
  326. return retval;
  327. }
  328. static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss)
  329. {
  330. if (t_node.children.size() < 2)
  331. {
  332. return {};
  333. } else {
  334. return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)};
  335. }
  336. }
  337. static dispatch::Param_Types get_arg_types(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
  338. std::vector<std::pair<std::string, Type_Info>> retval;
  339. for (const auto &child : t_node.children)
  340. {
  341. retval.push_back(get_arg_type(*child, t_ss));
  342. }
  343. return dispatch::Param_Types(std::move(retval));
  344. }
  345. };
  346. template<typename T>
  347. struct Equation_AST_Node final : AST_Node_Impl<T> {
  348. Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  349. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)),
  350. m_oper(Operators::to_operator(this->text))
  351. { assert(this->children.size() == 2); }
  352. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  353. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  354. Boxed_Value rhs = this->children[1]->eval(t_ss);
  355. Boxed_Value lhs = this->children[0]->eval(t_ss);
  356. if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() &&
  357. rhs.get_type_info().is_arithmetic())
  358. {
  359. try {
  360. return Boxed_Number::do_oper(m_oper, lhs, rhs);
  361. } catch (const std::exception &) {
  362. throw exception::eval_error("Error with unsupported arithmetic assignment operation");
  363. }
  364. } else if (m_oper == Operators::Opers::assign) {
  365. if (lhs.is_return_value()) {
  366. throw exception::eval_error("Error, cannot assign to temporary value.");
  367. }
  368. try {
  369. if (lhs.is_undef()) {
  370. if (!this->children.empty()
  371. && ((this->children[0]->identifier == AST_Node_Type::Reference)
  372. || (!this->children[0]->children.empty()
  373. && this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
  374. )
  375. )
  376. {
  377. /// \todo This does not handle the case of an unassigned reference variable
  378. /// being assigned outside of its declaration
  379. lhs.assign(rhs);
  380. lhs.reset_return_value();
  381. return rhs;
  382. } else {
  383. if (!rhs.is_return_value())
  384. {
  385. rhs = t_ss->call_function("clone", m_clone_loc, {rhs}, t_ss.conversions());
  386. }
  387. rhs.reset_return_value();
  388. }
  389. }
  390. try {
  391. return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
  392. }
  393. catch(const exception::dispatch_error &e){
  394. throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
  395. }
  396. }
  397. catch(const exception::dispatch_error &e){
  398. throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss);
  399. }
  400. }
  401. else if (this->text == ":=") {
  402. if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
  403. lhs.assign(rhs);
  404. lhs.reset_return_value();
  405. } else {
  406. throw exception::eval_error("Mismatched types in equation");
  407. }
  408. }
  409. else {
  410. try {
  411. return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
  412. } catch(const exception::dispatch_error &e){
  413. throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
  414. }
  415. }
  416. return rhs;
  417. }
  418. private:
  419. Operators::Opers m_oper;
  420. mutable std::atomic_uint_fast32_t m_loc = {0};
  421. mutable std::atomic_uint_fast32_t m_clone_loc = {0};
  422. };
  423. template<typename T>
  424. struct Global_Decl_AST_Node final : AST_Node_Impl<T> {
  425. Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  426. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { }
  427. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  428. const std::string &idname =
  429. [&]()->const std::string & {
  430. if (this->children[0]->identifier == AST_Node_Type::Reference) {
  431. return this->children[0]->children[0]->text;
  432. } else {
  433. return this->children[0]->text;
  434. }
  435. }();
  436. return t_ss->add_global_no_throw(Boxed_Value(), idname);
  437. }
  438. };
  439. template<typename T>
  440. struct Var_Decl_AST_Node final : AST_Node_Impl<T> {
  441. Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  442. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { }
  443. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  444. const std::string &idname = this->children[0]->text;
  445. try {
  446. Boxed_Value bv;
  447. t_ss.add_object(idname, bv);
  448. return bv;
  449. } catch (const exception::name_conflict_error &e) {
  450. throw exception::eval_error("Variable redefined '" + e.name() + "'");
  451. }
  452. }
  453. };
  454. template<typename T>
  455. struct Array_Call_AST_Node final : AST_Node_Impl<T> {
  456. Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  457. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { }
  458. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  459. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  460. const std::vector<Boxed_Value> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
  461. try {
  462. fpp.save_params(params);
  463. return t_ss->call_function("[]", m_loc, params, t_ss.conversions());
  464. }
  465. catch(const exception::dispatch_error &e){
  466. throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
  467. }
  468. }
  469. private:
  470. mutable std::atomic_uint_fast32_t m_loc = {0};
  471. };
  472. template<typename T>
  473. struct Dot_Access_AST_Node final : AST_Node_Impl<T> {
  474. Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  475. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)),
  476. m_fun_name(
  477. ((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))?
  478. this->children[1]->children[0]->text:this->children[1]->text) { }
  479. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  480. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  481. Boxed_Value retval = this->children[0]->eval(t_ss);
  482. std::vector<Boxed_Value> params{retval};
  483. bool has_function_params = false;
  484. if (this->children[1]->children.size() > 1) {
  485. has_function_params = true;
  486. for (const auto &child : this->children[1]->children[1]->children) {
  487. params.push_back(child->eval(t_ss));
  488. }
  489. }
  490. fpp.save_params(params);
  491. try {
  492. retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions());
  493. }
  494. catch(const exception::dispatch_error &e){
  495. if (e.functions.empty())
  496. {
  497. throw exception::eval_error("'" + m_fun_name + "' is not a function.");
  498. } else {
  499. throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss);
  500. }
  501. }
  502. catch(detail::Return_Value &rv) {
  503. retval = std::move(rv.retval);
  504. }
  505. if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
  506. try {
  507. retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[1]->children[1]->eval(t_ss)}, t_ss.conversions());
  508. }
  509. catch(const exception::dispatch_error &e){
  510. throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
  511. }
  512. }
  513. return retval;
  514. }
  515. private:
  516. mutable std::atomic_uint_fast32_t m_loc = {0};
  517. mutable std::atomic_uint_fast32_t m_array_loc = {0};
  518. const std::string m_fun_name;
  519. };
  520. template<typename T>
  521. struct Lambda_AST_Node final : AST_Node_Impl<T> {
  522. Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  523. AST_Node_Impl<T>(t_ast_node_text,
  524. AST_Node_Type::Lambda,
  525. std::move(t_loc),
  526. std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
  527. std::make_move_iterator(std::prev(t_children.end())))
  528. ),
  529. m_param_names(Arg_List_AST_Node<T>::get_arg_names(*this->children[1])),
  530. m_this_capture(has_this_capture(this->children[0]->children)),
  531. m_lambda_node(std::move(t_children.back()))
  532. { }
  533. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  534. const auto captures = [&]()->std::map<std::string, Boxed_Value>{
  535. std::map<std::string, Boxed_Value> named_captures;
  536. for (const auto &capture : this->children[0]->children) {
  537. named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
  538. }
  539. return named_captures;
  540. }();
  541. const auto numparams = this->children[1]->children.size();
  542. const auto param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
  543. std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
  544. return Boxed_Value(
  545. dispatch::make_dynamic_proxy_function(
  546. [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures,
  547. this_capture = this->m_this_capture] (const std::vector<Boxed_Value> &t_params)
  548. {
  549. return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture);
  550. },
  551. static_cast<int>(numparams), m_lambda_node, param_types
  552. )
  553. );
  554. }
  555. static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) {
  556. return std::any_of(std::begin(children), std::end(children),
  557. [](const auto &child){
  558. return child->children[0]->text == "this";
  559. }
  560. );
  561. }
  562. private:
  563. const std::vector<std::string> m_param_names;
  564. const bool m_this_capture = false;
  565. const std::shared_ptr<AST_Node_Impl<T>> m_lambda_node;
  566. };
  567. template<typename T>
  568. struct Scopeless_Block_AST_Node final : AST_Node_Impl<T> {
  569. Scopeless_Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  570. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) { }
  571. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  572. const auto num_children = this->children.size();
  573. for (size_t i = 0; i < num_children-1; ++i) {
  574. this->children[i]->eval(t_ss);
  575. }
  576. return this->children.back()->eval(t_ss);
  577. }
  578. };
  579. template<typename T>
  580. struct Block_AST_Node final : AST_Node_Impl<T> {
  581. Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  582. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { }
  583. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  584. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  585. const auto num_children = this->children.size();
  586. for (size_t i = 0; i < num_children-1; ++i) {
  587. this->children[i]->eval(t_ss);
  588. }
  589. return this->children.back()->eval(t_ss);
  590. }
  591. };
  592. template<typename T>
  593. struct Def_AST_Node final : AST_Node_Impl<T> {
  594. std::shared_ptr<AST_Node_Impl<T>> m_body_node;
  595. std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
  596. Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  597. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc),
  598. std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
  599. std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1)))
  600. ),
  601. m_body_node(get_body_node(std::move(t_children))),
  602. m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
  603. { }
  604. static std::shared_ptr<AST_Node_Impl<T>> get_guard_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec, bool has_guard)
  605. {
  606. if (has_guard) {
  607. return std::move(*std::prev(vec.end(), 2));
  608. } else {
  609. return {};
  610. }
  611. }
  612. static std::shared_ptr<AST_Node_Impl<T>> get_body_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec)
  613. {
  614. return std::move(vec.back());
  615. }
  616. static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset)
  617. {
  618. if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) {
  619. if (t_children.size() > 3 + offset) {
  620. return true;
  621. }
  622. }
  623. else {
  624. if (t_children.size() > 2 + offset) {
  625. return true;
  626. }
  627. }
  628. return false;
  629. }
  630. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  631. std::vector<std::string> t_param_names;
  632. size_t numparams = 0;
  633. dispatch::Param_Types param_types;
  634. if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
  635. numparams = this->children[1]->children.size();
  636. t_param_names = Arg_List_AST_Node<T>::get_arg_names(*this->children[1]);
  637. param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
  638. }
  639. std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
  640. std::shared_ptr<dispatch::Proxy_Function_Base> guard;
  641. if (m_guard_node) {
  642. guard = dispatch::make_dynamic_proxy_function(
  643. [engine, guardnode = m_guard_node, t_param_names](const std::vector<Boxed_Value> &t_params)
  644. {
  645. return detail::eval_function(engine, *guardnode, t_param_names, t_params);
  646. },
  647. static_cast<int>(numparams), m_guard_node);
  648. }
  649. try {
  650. const std::string & l_function_name = this->children[0]->text;
  651. t_ss->add(
  652. dispatch::make_dynamic_proxy_function(
  653. [engine, func_node = m_body_node, t_param_names](const std::vector<Boxed_Value> &t_params)
  654. {
  655. return detail::eval_function(engine, *func_node, t_param_names, t_params);
  656. },
  657. static_cast<int>(numparams), m_body_node,
  658. param_types, guard), l_function_name);
  659. } catch (const exception::name_conflict_error &e) {
  660. throw exception::eval_error("Function redefined '" + e.name() + "'");
  661. }
  662. return void_var();
  663. }
  664. };
  665. template<typename T>
  666. struct While_AST_Node final : AST_Node_Impl<T> {
  667. While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  668. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { }
  669. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  670. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  671. try {
  672. while (this->get_scoped_bool_condition(*this->children[0], t_ss)) {
  673. try {
  674. this->children[1]->eval(t_ss);
  675. } catch (detail::Continue_Loop &) {
  676. // we got a continue exception, which means all of the remaining
  677. // loop implementation is skipped and we just need to continue to
  678. // the next condition test
  679. }
  680. }
  681. } catch (detail::Break_Loop &) {
  682. // loop was broken intentionally
  683. }
  684. return void_var();
  685. }
  686. };
  687. template<typename T>
  688. struct Class_AST_Node final : AST_Node_Impl<T> {
  689. Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  690. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { }
  691. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  692. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  693. /// \todo do this better
  694. // put class name in current scope so it can be looked up by the attrs and methods
  695. t_ss.add_object("_current_class_name", const_var(this->children[0]->text));
  696. this->children[1]->eval(t_ss);
  697. return void_var();
  698. }
  699. };
  700. template<typename T>
  701. struct If_AST_Node final : AST_Node_Impl<T> {
  702. If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  703. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children))
  704. {
  705. assert(this->children.size() == 3);
  706. }
  707. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  708. if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) {
  709. return this->children[1]->eval(t_ss);
  710. } else {
  711. return this->children[2]->eval(t_ss);
  712. }
  713. }
  714. };
  715. template<typename T>
  716. struct Ranged_For_AST_Node final : AST_Node_Impl<T> {
  717. Ranged_For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  718. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children))
  719. { assert(this->children.size() == 3); }
  720. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  721. const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){
  722. uint_fast32_t hint = t_hint;
  723. auto funs = t_ss->get_function(t_name, hint);
  724. if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); }
  725. return std::move(funs.second);
  726. };
  727. const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {
  728. return dispatch::dispatch(*t_funcs, {t_param}, t_ss.conversions());
  729. };
  730. const std::string &loop_var_name = this->children[0]->text;
  731. Boxed_Value range_expression_result = this->children[1]->eval(t_ss);
  732. const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing){
  733. try {
  734. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  735. Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var());
  736. for (auto loop_var : ranged_thing) {
  737. obj = Boxed_Value(std::move(loop_var));
  738. try {
  739. this->children[2]->eval(t_ss);
  740. } catch (detail::Continue_Loop &) {
  741. }
  742. }
  743. } catch (detail::Break_Loop &) {
  744. // loop broken
  745. }
  746. return void_var();
  747. };
  748. if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::vector<Boxed_Value>))) {
  749. return do_loop(boxed_cast<const std::vector<Boxed_Value> &>(range_expression_result));
  750. } else if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::map<std::string, Boxed_Value>))) {
  751. return do_loop(boxed_cast<const std::map<std::string, Boxed_Value> &>(range_expression_result));
  752. } else {
  753. const auto range_funcs = get_function("range", m_range_loc);
  754. const auto empty_funcs = get_function("empty", m_empty_loc);
  755. const auto front_funcs = get_function("front", m_front_loc);
  756. const auto pop_front_funcs = get_function("pop_front", m_pop_front_loc);
  757. try {
  758. const auto range_obj = call_function(range_funcs, range_expression_result);
  759. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  760. Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var());
  761. while (!boxed_cast<bool>(call_function(empty_funcs, range_obj))) {
  762. obj = call_function(front_funcs, range_obj);
  763. try {
  764. this->children[2]->eval(t_ss);
  765. } catch (detail::Continue_Loop &) {
  766. }
  767. call_function(pop_front_funcs, range_obj);
  768. }
  769. } catch (detail::Break_Loop &) {
  770. // loop broken
  771. }
  772. return void_var();
  773. }
  774. }
  775. private:
  776. mutable std::atomic_uint_fast32_t m_range_loc = {0};
  777. mutable std::atomic_uint_fast32_t m_empty_loc = {0};
  778. mutable std::atomic_uint_fast32_t m_front_loc = {0};
  779. mutable std::atomic_uint_fast32_t m_pop_front_loc = {0};
  780. };
  781. template<typename T>
  782. struct For_AST_Node final : AST_Node_Impl<T> {
  783. For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  784. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children))
  785. { assert(this->children.size() == 4); }
  786. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  787. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  788. try {
  789. for (
  790. this->children[0]->eval(t_ss);
  791. this->get_scoped_bool_condition(*this->children[1], t_ss);
  792. this->children[2]->eval(t_ss)
  793. ) {
  794. try {
  795. // Body of Loop
  796. this->children[3]->eval(t_ss);
  797. } catch (detail::Continue_Loop &) {
  798. // we got a continue exception, which means all of the remaining
  799. // loop implementation is skipped and we just need to continue to
  800. // the next iteration step
  801. }
  802. }
  803. } catch (detail::Break_Loop &) {
  804. // loop broken
  805. }
  806. return void_var();
  807. }
  808. };
  809. template<typename T>
  810. struct Switch_AST_Node final : AST_Node_Impl<T> {
  811. Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  812. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { }
  813. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  814. bool breaking = false;
  815. size_t currentCase = 1;
  816. bool hasMatched = false;
  817. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  818. Boxed_Value match_value(this->children[0]->eval(t_ss));
  819. while (!breaking && (currentCase < this->children.size())) {
  820. try {
  821. if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
  822. //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
  823. try {
  824. if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) {
  825. this->children[currentCase]->eval(t_ss);
  826. hasMatched = true;
  827. }
  828. }
  829. catch (const exception::bad_boxed_cast &) {
  830. throw exception::eval_error("Internal error: case guard evaluation not boolean");
  831. }
  832. }
  833. else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
  834. this->children[currentCase]->eval(t_ss);
  835. hasMatched = true;
  836. }
  837. }
  838. catch (detail::Break_Loop &) {
  839. breaking = true;
  840. }
  841. ++currentCase;
  842. }
  843. return void_var();
  844. }
  845. mutable std::atomic_uint_fast32_t m_loc = {0};
  846. };
  847. template<typename T>
  848. struct Case_AST_Node final : AST_Node_Impl<T> {
  849. Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  850. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children))
  851. { assert(this->children.size() == 2); /* how many children does it have? */ }
  852. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  853. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  854. this->children[1]->eval(t_ss);
  855. return void_var();
  856. }
  857. };
  858. template<typename T>
  859. struct Default_AST_Node final : AST_Node_Impl<T> {
  860. Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  861. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children))
  862. { assert(this->children.size() == 1); }
  863. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  864. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  865. this->children[0]->eval(t_ss);
  866. return void_var();
  867. }
  868. };
  869. template<typename T>
  870. struct Inline_Array_AST_Node final : AST_Node_Impl<T> {
  871. Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  872. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { }
  873. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  874. try {
  875. std::vector<Boxed_Value> vec;
  876. if (!this->children.empty()) {
  877. vec.reserve(this->children[0]->children.size());
  878. for (const auto &child : this->children[0]->children) {
  879. auto obj = child->eval(t_ss);
  880. if (!obj.is_return_value()) {
  881. vec.push_back(t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions()));
  882. } else {
  883. vec.push_back(std::move(obj));
  884. }
  885. }
  886. }
  887. return const_var(std::move(vec));
  888. }
  889. catch (const exception::dispatch_error &) {
  890. throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements");
  891. }
  892. }
  893. private:
  894. mutable std::atomic_uint_fast32_t m_loc = {0};
  895. };
  896. template<typename T>
  897. struct Inline_Map_AST_Node final : AST_Node_Impl<T> {
  898. Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  899. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { }
  900. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
  901. {
  902. try {
  903. std::map<std::string, Boxed_Value> retval;
  904. for (const auto &child : this->children[0]->children) {
  905. auto obj = child->children[1]->eval(t_ss);
  906. if (!obj.is_return_value()) {
  907. obj = t_ss->call_function("clone", m_loc, {obj}, t_ss.conversions());
  908. }
  909. retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
  910. }
  911. return const_var(std::move(retval));
  912. }
  913. catch (const exception::dispatch_error &e) {
  914. throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss);
  915. }
  916. }
  917. private:
  918. mutable std::atomic_uint_fast32_t m_loc = {0};
  919. };
  920. template<typename T>
  921. struct Return_AST_Node final : AST_Node_Impl<T> {
  922. Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  923. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { }
  924. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  925. if (!this->children.empty()) {
  926. throw detail::Return_Value(this->children[0]->eval(t_ss));
  927. }
  928. else {
  929. throw detail::Return_Value(void_var());
  930. }
  931. }
  932. };
  933. template<typename T>
  934. struct File_AST_Node final : AST_Node_Impl<T> {
  935. File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  936. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { }
  937. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  938. try {
  939. const auto num_children = this->children.size();
  940. if (num_children > 0) {
  941. for (size_t i = 0; i < num_children-1; ++i) {
  942. this->children[i]->eval(t_ss);
  943. }
  944. return this->children.back()->eval(t_ss);
  945. } else {
  946. return void_var();
  947. }
  948. } catch (const detail::Continue_Loop &) {
  949. throw exception::eval_error("Unexpected `continue` statement outside of a loop");
  950. } catch (const detail::Break_Loop &) {
  951. throw exception::eval_error("Unexpected `break` statement outside of a loop");
  952. }
  953. }
  954. };
  955. template<typename T>
  956. struct Reference_AST_Node final : AST_Node_Impl<T> {
  957. Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  958. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children))
  959. { assert(this->children.size() == 1); }
  960. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  961. Boxed_Value bv;
  962. t_ss.add_object(this->children[0]->text, bv);
  963. return bv;
  964. }
  965. };
  966. template<typename T>
  967. struct Prefix_AST_Node final : AST_Node_Impl<T> {
  968. Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  969. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)),
  970. m_oper(Operators::to_operator(this->text, true))
  971. { }
  972. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  973. Boxed_Value bv(this->children[0]->eval(t_ss));
  974. try {
  975. // short circuit arithmetic operations
  976. if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic())
  977. {
  978. return Boxed_Number::do_oper(m_oper, bv);
  979. } else {
  980. chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
  981. fpp.save_params({bv});
  982. return t_ss->call_function(this->text, m_loc, {std::move(bv)}, t_ss.conversions());
  983. }
  984. } catch (const exception::dispatch_error &e) {
  985. throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
  986. }
  987. }
  988. private:
  989. Operators::Opers m_oper = Operators::Opers::invalid;
  990. mutable std::atomic_uint_fast32_t m_loc = {0};
  991. };
  992. template<typename T>
  993. struct Break_AST_Node final : AST_Node_Impl<T> {
  994. Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  995. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { }
  996. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
  997. throw detail::Break_Loop();
  998. }
  999. };
  1000. template<typename T>
  1001. struct Continue_AST_Node final : AST_Node_Impl<T> {
  1002. Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1003. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { }
  1004. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
  1005. throw detail::Continue_Loop();
  1006. }
  1007. };
  1008. template<typename T>
  1009. struct Noop_AST_Node final : AST_Node_Impl<T> {
  1010. Noop_AST_Node() :
  1011. AST_Node_Impl<T>("", AST_Node_Type::Noop, Parse_Location())
  1012. { }
  1013. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
  1014. // It's a no-op, that evaluates to "void"
  1015. return val;
  1016. }
  1017. Boxed_Value val = void_var();
  1018. };
  1019. template<typename T>
  1020. struct Map_Pair_AST_Node final : AST_Node_Impl<T> {
  1021. Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1022. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { }
  1023. };
  1024. template<typename T>
  1025. struct Value_Range_AST_Node final : AST_Node_Impl<T> {
  1026. Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1027. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { }
  1028. };
  1029. template<typename T>
  1030. struct Inline_Range_AST_Node final : AST_Node_Impl<T> {
  1031. Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1032. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { }
  1033. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  1034. try {
  1035. auto oper1 = this->children[0]->children[0]->children[0]->eval(t_ss);
  1036. auto oper2 = this->children[0]->children[0]->children[1]->eval(t_ss);
  1037. return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions());
  1038. }
  1039. catch (const exception::dispatch_error &e) {
  1040. throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
  1041. }
  1042. }
  1043. private:
  1044. mutable std::atomic_uint_fast32_t m_loc = {0};
  1045. };
  1046. template<typename T>
  1047. struct Try_AST_Node final : AST_Node_Impl<T> {
  1048. Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1049. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { }
  1050. Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const
  1051. {
  1052. Boxed_Value retval;
  1053. size_t end_point = this->children.size();
  1054. if (this->children.back()->identifier == AST_Node_Type::Finally) {
  1055. assert(end_point > 0);
  1056. end_point = this->children.size() - 1;
  1057. }
  1058. for (size_t i = 1; i < end_point; ++i) {
  1059. chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss);
  1060. auto &catch_block = *this->children[i];
  1061. if (catch_block.children.size() == 1) {
  1062. //No variable capture, no guards
  1063. retval = catch_block.children[0]->eval(t_ss);
  1064. break;
  1065. } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) {
  1066. const auto name = Arg_List_AST_Node<T>::get_arg_name(*catch_block.children[0]);
  1067. if (dispatch::Param_Types(
  1068. std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)}
  1069. ).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first)
  1070. {
  1071. t_ss.add_object(name, t_except);
  1072. if (catch_block.children.size() == 2) {
  1073. //Variable capture, no guards
  1074. retval = catch_block.children[1]->eval(t_ss);
  1075. break;
  1076. }
  1077. else if (catch_block.children.size() == 3) {
  1078. //Variable capture, guards
  1079. bool guard = false;
  1080. try {
  1081. guard = boxed_cast<bool>(catch_block.children[1]->eval(t_ss));
  1082. } catch (const exception::bad_boxed_cast &) {
  1083. if (this->children.back()->identifier == AST_Node_Type::Finally) {
  1084. this->children.back()->children[0]->eval(t_ss);
  1085. }
  1086. throw exception::eval_error("Guard condition not boolean");
  1087. }
  1088. if (guard) {
  1089. retval = catch_block.children[2]->eval(t_ss);
  1090. break;
  1091. }
  1092. }
  1093. }
  1094. }
  1095. else {
  1096. if (this->children.back()->identifier == AST_Node_Type::Finally) {
  1097. this->children.back()->children[0]->eval(t_ss);
  1098. }
  1099. throw exception::eval_error("Internal error: catch block size unrecognized");
  1100. }
  1101. }
  1102. return retval;
  1103. }
  1104. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
  1105. Boxed_Value retval;
  1106. chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
  1107. try {
  1108. retval = this->children[0]->eval(t_ss);
  1109. }
  1110. catch (const exception::eval_error &e) {
  1111. retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
  1112. }
  1113. catch (const std::runtime_error &e) {
  1114. retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
  1115. }
  1116. catch (const std::out_of_range &e) {
  1117. retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
  1118. }
  1119. catch (const std::exception &e) {
  1120. retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
  1121. }
  1122. catch (Boxed_Value &e) {
  1123. retval = handle_exception(t_ss, e);
  1124. }
  1125. catch (...) {
  1126. if (this->children.back()->identifier == AST_Node_Type::Finally) {
  1127. this->children.back()->children[0]->eval(t_ss);
  1128. }
  1129. throw;
  1130. }
  1131. if (this->children.back()->identifier == AST_Node_Type::Finally) {
  1132. retval = this->children.back()->children[0]->eval(t_ss);
  1133. }
  1134. return retval;
  1135. }
  1136. };
  1137. template<typename T>
  1138. struct Catch_AST_Node final : AST_Node_Impl<T> {
  1139. Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1140. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { }
  1141. };
  1142. template<typename T>
  1143. struct Finally_AST_Node final : AST_Node_Impl<T> {
  1144. Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1145. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { }
  1146. };
  1147. template<typename T>
  1148. struct Method_AST_Node final : AST_Node_Impl<T> {
  1149. std::shared_ptr<AST_Node_Impl<T>> m_body_node;
  1150. std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
  1151. Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1152. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc),
  1153. std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
  1154. std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1)))
  1155. ),
  1156. m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))),
  1157. m_guard_node(Def_AST_Node<T>::get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
  1158. {
  1159. }
  1160. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
  1161. AST_Node_Impl_Ptr<T> guardnode;
  1162. const std::string & class_name = this->children[0]->text;
  1163. //The first param of a method is always the implied this ptr.
  1164. std::vector<std::string> t_param_names{"this"};
  1165. dispatch::Param_Types param_types;
  1166. if ((this->children.size() > 2)
  1167. && (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
  1168. auto args = Arg_List_AST_Node<T>::get_arg_names(*this->children[2]);
  1169. t_param_names.insert(t_param_names.end(), args.begin(), args.end());
  1170. param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[2], t_ss);
  1171. }
  1172. const size_t numparams = t_param_names.size();
  1173. std::shared_ptr<dispatch::Proxy_Function_Base> guard;
  1174. std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
  1175. if (m_guard_node) {
  1176. guard = dispatch::make_dynamic_proxy_function(
  1177. [engine, t_param_names, guardnode = m_guard_node](const std::vector<Boxed_Value> &t_params) {
  1178. return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params);
  1179. },
  1180. static_cast<int>(numparams), m_guard_node);
  1181. }
  1182. try {
  1183. const std::string & function_name = this->children[1]->text;
  1184. if (function_name == class_name) {
  1185. param_types.push_front(class_name, Type_Info());
  1186. t_ss->add(
  1187. std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
  1188. dispatch::make_dynamic_proxy_function(
  1189. [engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
  1190. return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
  1191. },
  1192. static_cast<int>(numparams), m_body_node, param_types, guard
  1193. )
  1194. ),
  1195. function_name);
  1196. } else {
  1197. // if the type is unknown, then this generates a function that looks up the type
  1198. // at runtime. Defining the type first before this is called is better
  1199. auto type = t_ss->get_type(class_name, false);
  1200. param_types.push_front(class_name, type);
  1201. t_ss->add(
  1202. std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
  1203. dispatch::make_dynamic_proxy_function(
  1204. [engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
  1205. return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
  1206. },
  1207. static_cast<int>(numparams), m_body_node, param_types, guard), type),
  1208. function_name);
  1209. }
  1210. } catch (const exception::name_conflict_error &e) {
  1211. std::cout << "Method!!" << std::endl;
  1212. throw exception::eval_error("Method redefined '" + e.name() + "'");
  1213. }
  1214. return void_var();
  1215. }
  1216. };
  1217. template<typename T>
  1218. struct Attr_Decl_AST_Node final : AST_Node_Impl<T> {
  1219. Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1220. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { }
  1221. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
  1222. {
  1223. std::string class_name = this->children[0]->text;
  1224. try {
  1225. std::string attr_name = this->children[1]->text;
  1226. t_ss->add(
  1227. std::make_shared<dispatch::detail::Dynamic_Object_Function>(
  1228. std::move(class_name),
  1229. fun([attr_name](dispatch::Dynamic_Object &t_obj) {
  1230. return t_obj.get_attr(attr_name);
  1231. }),
  1232. true
  1233. ), this->children[1]->text);
  1234. } catch (const exception::name_conflict_error &e) {
  1235. throw exception::eval_error("Attribute redefined '" + e.name() + "'");
  1236. }
  1237. return void_var();
  1238. }
  1239. };
  1240. template<typename T>
  1241. struct Logical_And_AST_Node final : AST_Node_Impl<T> {
  1242. Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1243. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children))
  1244. { assert(this->children.size() == 2); }
  1245. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
  1246. {
  1247. return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
  1248. && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
  1249. }
  1250. };
  1251. template<typename T>
  1252. struct Logical_Or_AST_Node final : AST_Node_Impl<T> {
  1253. Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
  1254. AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children))
  1255. { assert(this->children.size() == 2); }
  1256. Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
  1257. {
  1258. return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
  1259. || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
  1260. }
  1261. };
  1262. }
  1263. }
  1264. #endif /* CHAISCRIPT_EVAL_HPP_ */