1 // This file is distributed under the BSD License. 2 // See "license.txt" for details. 3 // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) 4 // Copyright 2009-2017, Jason Turner (jason@emptycrate.com) 5 // http://www.chaiscript.com 6 7 // This is an open source non-commercial project. Dear PVS-Studio, please check it. 8 // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com 9 10 11 #ifndef CHAISCRIPT_EVAL_HPP_ 12 #define CHAISCRIPT_EVAL_HPP_ 13 14 #include <exception> 15 #include <functional> 16 #include <limits> 17 #include <map> 18 #include <memory> 19 #include <ostream> 20 #include <stdexcept> 21 #include <string> 22 #include <vector> 23 24 #include "../chaiscript_defines.hpp" 25 #include "../dispatchkit/boxed_cast.hpp" 26 #include "../dispatchkit/boxed_number.hpp" 27 #include "../dispatchkit/boxed_value.hpp" 28 #include "../dispatchkit/dispatchkit.hpp" 29 #include "../dispatchkit/dynamic_object_detail.hpp" 30 #include "../dispatchkit/proxy_functions.hpp" 31 #include "../dispatchkit/proxy_functions_detail.hpp" 32 #include "../dispatchkit/register_function.hpp" 33 #include "../dispatchkit/type_info.hpp" 34 #include "chaiscript_algebraic.hpp" 35 #include "chaiscript_common.hpp" 36 37 namespace chaiscript { 38 namespace exception { 39 class bad_boxed_cast; 40 } // namespace exception 41 } // namespace chaiscript 42 43 namespace chaiscript 44 { 45 /// \brief Classes and functions that are part of the runtime eval system 46 namespace eval 47 { 48 template<typename T> struct AST_Node_Impl; 49 50 template<typename T> using AST_Node_Impl_Ptr = typename std::unique_ptr<AST_Node_Impl<T>>; 51 52 namespace detail 53 { 54 /// Helper function that will set up the scope around a function call, including handling the named function parameters 55 template<typename T> 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)56 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) { 57 chaiscript::detail::Dispatch_State state(t_ss); 58 59 const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ 60 auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); 61 if (!stack.empty() && stack.back().first == "__this") { 62 return &stack.back().second; 63 } else if (!t_vals.empty()) { 64 return &t_vals[0]; 65 } else { 66 return nullptr; 67 } 68 }(); 69 70 chaiscript::eval::detail::Stack_Push_Pop tpp(state); 71 if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); } 72 73 if (t_locals) { 74 for (const auto &local : *t_locals) { 75 state.add_object(local.first, local.second); 76 } 77 } 78 79 for (size_t i = 0; i < t_param_names.size(); ++i) { 80 if (t_param_names[i] != "this") { 81 state.add_object(t_param_names[i], t_vals[i]); 82 } 83 } 84 85 try { 86 return t_node.eval(state); 87 } catch (detail::Return_Value &rv) { 88 return std::move(rv.retval); 89 } 90 } 91 clone_if_necessary(Boxed_Value incoming,std::atomic_uint_fast32_t & t_loc,const chaiscript::detail::Dispatch_State & t_ss)92 inline Boxed_Value clone_if_necessary(Boxed_Value incoming, std::atomic_uint_fast32_t &t_loc, const chaiscript::detail::Dispatch_State &t_ss) 93 { 94 if (!incoming.is_return_value()) 95 { 96 if (incoming.get_type_info().is_arithmetic()) { 97 return Boxed_Number::clone(incoming); 98 } else if (incoming.get_type_info().bare_equal_type_info(typeid(bool))) { 99 return Boxed_Value(*static_cast<const bool*>(incoming.get_const_ptr())); 100 } else { 101 return t_ss->call_function("clone", t_loc, {incoming}, t_ss.conversions()); 102 } 103 } else { 104 incoming.reset_return_value(); 105 return incoming; 106 } 107 } 108 } 109 110 template<typename T> 111 struct AST_Node_Impl : AST_Node 112 { AST_Node_Implchaiscript::eval::AST_Node_Impl113 AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, 114 std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>()) 115 : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)), 116 children(std::move(t_children)) 117 { 118 } 119 get_scoped_bool_conditionchaiscript::eval::AST_Node_Impl120 static bool get_scoped_bool_condition(const AST_Node_Impl<T> &node, const chaiscript::detail::Dispatch_State &t_ss) { 121 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 122 return get_bool_condition(node.eval(t_ss), t_ss); 123 } 124 125 get_childrenchaiscript::eval::AST_Node_Impl126 std::vector<std::reference_wrapper<AST_Node>> get_children() const final { 127 std::vector<std::reference_wrapper<AST_Node>> retval; 128 retval.reserve(children.size()); 129 for (auto &&child : children) { 130 retval.emplace_back(*child); 131 } 132 133 return retval; 134 } 135 evalchaiscript::eval::AST_Node_Impl136 Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final 137 { 138 try { 139 T::trace(t_e, this); 140 return eval_internal(t_e); 141 } catch (exception::eval_error &ee) { 142 ee.call_stack.push_back(*this); 143 throw; 144 } 145 } 146 147 std::vector<AST_Node_Impl_Ptr<T>> children; 148 149 protected: eval_internalchaiscript::eval::AST_Node_Impl150 virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const 151 { 152 throw std::runtime_error("Undispatched ast_node (internal error)"); 153 } 154 }; 155 156 157 template<typename T> 158 struct Compiled_AST_Node : AST_Node_Impl<T> { Compiled_AST_Nodechaiscript::eval::Compiled_AST_Node159 Compiled_AST_Node(AST_Node_Impl_Ptr<T> t_original_node, std::vector<AST_Node_Impl_Ptr<T>> t_children, 160 std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) : 161 AST_Node_Impl<T>(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)), 162 m_func(std::move(t_func)), 163 m_original_node(std::move(t_original_node)) 164 { } 165 eval_internalchaiscript::eval::Compiled_AST_Node166 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 167 return m_func(this->children, t_ss); 168 } 169 170 std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func; 171 AST_Node_Impl_Ptr<T> m_original_node; 172 }; 173 174 175 template<typename T> 176 struct Fold_Right_Binary_Operator_AST_Node : AST_Node_Impl<T> { Fold_Right_Binary_Operator_AST_Nodechaiscript::eval::Fold_Right_Binary_Operator_AST_Node177 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) : 178 AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)), 179 m_oper(Operators::to_operator(t_oper)), 180 m_rhs(std::move(t_rhs)) 181 { } 182 eval_internalchaiscript::eval::Fold_Right_Binary_Operator_AST_Node183 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 184 return do_oper(t_ss, this->text, this->children[0]->eval(t_ss)); 185 } 186 187 protected: do_operchaiscript::eval::Fold_Right_Binary_Operator_AST_Node188 Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, 189 const std::string &t_oper_string, const Boxed_Value &t_lhs) const 190 { 191 try { 192 if (t_lhs.get_type_info().is_arithmetic()) 193 { 194 // If it's an arithmetic operation we want to short circuit dispatch 195 try{ 196 return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs); 197 } catch (const chaiscript::exception::arithmetic_error &) { 198 throw; 199 } catch (...) { 200 throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); 201 } 202 } else { 203 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 204 fpp.save_params({t_lhs, m_rhs}); 205 return t_ss->call_function(t_oper_string, m_loc, {t_lhs, m_rhs}, t_ss.conversions()); 206 } 207 } 208 catch(const exception::dispatch_error &e){ 209 throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); 210 } 211 } 212 213 private: 214 Operators::Opers m_oper; 215 Boxed_Value m_rhs; 216 mutable std::atomic_uint_fast32_t m_loc = {0}; 217 }; 218 219 220 template<typename T> 221 struct Binary_Operator_AST_Node : AST_Node_Impl<T> { Binary_Operator_AST_Nodechaiscript::eval::Binary_Operator_AST_Node222 Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 223 AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)), 224 m_oper(Operators::to_operator(t_oper)) 225 { } 226 eval_internalchaiscript::eval::Binary_Operator_AST_Node227 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 228 auto lhs = this->children[0]->eval(t_ss); 229 auto rhs = this->children[1]->eval(t_ss); 230 return do_oper(t_ss, m_oper, this->text, lhs, rhs); 231 } 232 233 protected: do_operchaiscript::eval::Binary_Operator_AST_Node234 Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, 235 Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const 236 { 237 try { 238 if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic()) 239 { 240 // If it's an arithmetic operation we want to short circuit dispatch 241 try{ 242 return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs); 243 } catch (const chaiscript::exception::arithmetic_error &) { 244 throw; 245 } catch (...) { 246 throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); 247 } 248 } else { 249 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 250 fpp.save_params({t_lhs, t_rhs}); 251 return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions()); 252 } 253 } 254 catch(const exception::dispatch_error &e){ 255 throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); 256 } 257 } 258 259 private: 260 Operators::Opers m_oper; 261 mutable std::atomic_uint_fast32_t m_loc = {0}; 262 }; 263 264 265 template<typename T> 266 struct Constant_AST_Node final : AST_Node_Impl<T> { Constant_AST_Nodechaiscript::eval::Constant_AST_Node267 Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value) 268 : AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)), 269 m_value(std::move(t_value)) 270 { 271 } 272 Constant_AST_Nodechaiscript::eval::Constant_AST_Node273 explicit Constant_AST_Node(Boxed_Value t_value) 274 : AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()), 275 m_value(std::move(t_value)) 276 { 277 } 278 eval_internalchaiscript::eval::Constant_AST_Node279 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override { 280 return m_value; 281 } 282 283 Boxed_Value m_value; 284 }; 285 286 template<typename T> 287 struct Id_AST_Node final : AST_Node_Impl<T> { Id_AST_Nodechaiscript::eval::Id_AST_Node288 Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) : 289 AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)) 290 { } 291 eval_internalchaiscript::eval::Id_AST_Node292 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 293 try { 294 return t_ss.get_object(this->text, m_loc); 295 } 296 catch (std::exception &) { 297 throw exception::eval_error("Can not find object: " + this->text); 298 } 299 } 300 301 private: 302 mutable std::atomic_uint_fast32_t m_loc = {0}; 303 }; 304 305 template<typename T> 306 struct Fun_Call_AST_Node : AST_Node_Impl<T> { Fun_Call_AST_Nodechaiscript::eval::Fun_Call_AST_Node307 Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 308 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { 309 assert(!this->children.empty()); 310 } 311 312 template<bool Save_Params> do_eval_internalchaiscript::eval::Fun_Call_AST_Node313 Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const 314 { 315 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 316 317 std::vector<Boxed_Value> params; 318 319 params.reserve(this->children[1]->children.size()); 320 for (const auto &child : this->children[1]->children) { 321 params.push_back(child->eval(t_ss)); 322 } 323 324 if (Save_Params) { 325 fpp.save_params(params); 326 } 327 328 Boxed_Value fn(this->children[0]->eval(t_ss)); 329 330 using ConstFunctionTypePtr = const dispatch::Proxy_Function_Base *; 331 try { 332 return (*t_ss->boxed_cast<ConstFunctionTypePtr>(fn))(params, t_ss.conversions()); 333 } 334 catch(const exception::dispatch_error &e){ 335 throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss); 336 } 337 catch(const exception::bad_boxed_cast &){ 338 try { 339 using ConstFunctionTypeRef = const Const_Proxy_Function &; 340 Const_Proxy_Function f = t_ss->boxed_cast<ConstFunctionTypeRef>(fn); 341 // handle the case where there is only 1 function to try to call and dispatch fails on it 342 throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss); 343 } catch (const exception::bad_boxed_cast &) { 344 throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function."); 345 } 346 } 347 catch(const exception::arity_error &e){ 348 throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); 349 } 350 catch(const exception::guard_error &e){ 351 throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); 352 } 353 catch(detail::Return_Value &rv) { 354 return rv.retval; 355 } 356 } 357 eval_internalchaiscript::eval::Fun_Call_AST_Node358 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 359 { 360 return do_eval_internal<true>(t_ss); 361 } 362 363 }; 364 365 366 template<typename T> 367 struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node<T> { Unused_Return_Fun_Call_AST_Nodechaiscript::eval::Unused_Return_Fun_Call_AST_Node368 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) : 369 Fun_Call_AST_Node<T>(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { } 370 eval_internalchaiscript::eval::Unused_Return_Fun_Call_AST_Node371 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 372 { 373 return this->template do_eval_internal<false>(t_ss); 374 } 375 }; 376 377 378 379 380 381 template<typename T> 382 struct Arg_AST_Node final : AST_Node_Impl<T> { Arg_AST_Nodechaiscript::eval::Arg_AST_Node383 Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 384 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { } 385 386 }; 387 388 template<typename T> 389 struct Arg_List_AST_Node final : AST_Node_Impl<T> { Arg_List_AST_Nodechaiscript::eval::Arg_List_AST_Node390 Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 391 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { } 392 393 get_arg_namechaiscript::eval::Arg_List_AST_Node394 static std::string get_arg_name(const AST_Node_Impl<T> &t_node) { 395 if (t_node.children.empty()) 396 { 397 return t_node.text; 398 } else if (t_node.children.size() == 1) { 399 return t_node.children[0]->text; 400 } else { 401 return t_node.children[1]->text; 402 } 403 } 404 get_arg_nameschaiscript::eval::Arg_List_AST_Node405 static std::vector<std::string> get_arg_names(const AST_Node_Impl<T> &t_node) { 406 std::vector<std::string> retval; 407 408 for (const auto &node : t_node.children) 409 { 410 retval.push_back(get_arg_name(*node)); 411 } 412 413 return retval; 414 } 415 get_arg_typechaiscript::eval::Arg_List_AST_Node416 static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) 417 { 418 if (t_node.children.size() < 2) 419 { 420 return {}; 421 } else { 422 return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)}; 423 } 424 } 425 get_arg_typeschaiscript::eval::Arg_List_AST_Node426 static dispatch::Param_Types get_arg_types(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) { 427 std::vector<std::pair<std::string, Type_Info>> retval; 428 429 for (const auto &child : t_node.children) 430 { 431 retval.push_back(get_arg_type(*child, t_ss)); 432 } 433 434 return dispatch::Param_Types(std::move(retval)); 435 } 436 }; 437 438 template<typename T> 439 struct Equation_AST_Node final : AST_Node_Impl<T> { Equation_AST_Nodechaiscript::eval::Equation_AST_Node440 Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 441 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)), 442 m_oper(Operators::to_operator(this->text)) 443 { assert(this->children.size() == 2); } 444 445 eval_internalchaiscript::eval::Equation_AST_Node446 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 447 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 448 Boxed_Value rhs = this->children[1]->eval(t_ss); 449 Boxed_Value lhs = this->children[0]->eval(t_ss); 450 451 if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() && 452 rhs.get_type_info().is_arithmetic()) 453 { 454 try { 455 return Boxed_Number::do_oper(m_oper, lhs, rhs); 456 } catch (const std::exception &) { 457 throw exception::eval_error("Error with unsupported arithmetic assignment operation"); 458 } 459 } else if (m_oper == Operators::Opers::assign) { 460 if (lhs.is_return_value()) { 461 throw exception::eval_error("Error, cannot assign to temporary value."); 462 } 463 464 try { 465 466 if (lhs.is_undef()) { 467 if (!this->children.empty() 468 && ((this->children[0]->identifier == AST_Node_Type::Reference) 469 || (!this->children[0]->children.empty() 470 && this->children[0]->children[0]->identifier == AST_Node_Type::Reference) 471 ) 472 ) 473 474 { 475 /// \todo This does not handle the case of an unassigned reference variable 476 /// being assigned outside of its declaration 477 lhs.assign(rhs); 478 lhs.reset_return_value(); 479 return rhs; 480 } else { 481 rhs = detail::clone_if_necessary(std::move(rhs), m_clone_loc, t_ss); 482 } 483 } 484 485 try { 486 return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions()); 487 } 488 catch(const exception::dispatch_error &e){ 489 throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); 490 } 491 } 492 catch(const exception::dispatch_error &e){ 493 throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss); 494 } 495 } 496 else if (this->text == ":=") { 497 if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) { 498 lhs.assign(rhs); 499 lhs.reset_return_value(); 500 } else { 501 throw exception::eval_error("Mismatched types in equation"); 502 } 503 } 504 else { 505 try { 506 return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions()); 507 } catch(const exception::dispatch_error &e){ 508 throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); 509 } 510 } 511 512 return rhs; 513 } 514 515 private: 516 Operators::Opers m_oper; 517 mutable std::atomic_uint_fast32_t m_loc = {0}; 518 mutable std::atomic_uint_fast32_t m_clone_loc = {0}; 519 }; 520 521 template<typename T> 522 struct Global_Decl_AST_Node final : AST_Node_Impl<T> { Global_Decl_AST_Nodechaiscript::eval::Global_Decl_AST_Node523 Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 524 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { } 525 eval_internalchaiscript::eval::Global_Decl_AST_Node526 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 527 const std::string &idname = 528 [&]()->const std::string & { 529 if (this->children[0]->identifier == AST_Node_Type::Reference) { 530 return this->children[0]->children[0]->text; 531 } else { 532 return this->children[0]->text; 533 } 534 }(); 535 536 return t_ss->add_global_no_throw(Boxed_Value(), idname); 537 538 } 539 }; 540 541 542 template<typename T> 543 struct Var_Decl_AST_Node final : AST_Node_Impl<T> { Var_Decl_AST_Nodechaiscript::eval::Var_Decl_AST_Node544 Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 545 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { } 546 eval_internalchaiscript::eval::Var_Decl_AST_Node547 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 548 const std::string &idname = this->children[0]->text; 549 550 try { 551 Boxed_Value bv; 552 t_ss.add_object(idname, bv); 553 return bv; 554 } catch (const exception::name_conflict_error &e) { 555 throw exception::eval_error("Variable redefined '" + e.name() + "'"); 556 } 557 } 558 }; 559 560 template<typename T> 561 struct Assign_Decl_AST_Node final : AST_Node_Impl<T> { Assign_Decl_AST_Nodechaiscript::eval::Assign_Decl_AST_Node562 Assign_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 563 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Assign_Decl, std::move(t_loc), std::move(t_children)) { } 564 eval_internalchaiscript::eval::Assign_Decl_AST_Node565 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 566 const std::string &idname = this->children[0]->text; 567 568 try { 569 Boxed_Value bv(detail::clone_if_necessary(this->children[1]->eval(t_ss), m_loc, t_ss)); 570 bv.reset_return_value(); 571 t_ss.add_object(idname, bv); 572 return bv; 573 } catch (const exception::name_conflict_error &e) { 574 throw exception::eval_error("Variable redefined '" + e.name() + "'"); 575 } 576 } 577 private: 578 mutable std::atomic_uint_fast32_t m_loc = {0}; 579 }; 580 581 582 template<typename T> 583 struct Array_Call_AST_Node final : AST_Node_Impl<T> { Array_Call_AST_Nodechaiscript::eval::Array_Call_AST_Node584 Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 585 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { } 586 eval_internalchaiscript::eval::Array_Call_AST_Node587 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 588 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 589 590 const std::vector<Boxed_Value> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; 591 592 try { 593 fpp.save_params(params); 594 return t_ss->call_function("[]", m_loc, params, t_ss.conversions()); 595 } 596 catch(const exception::dispatch_error &e){ 597 throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); 598 } 599 } 600 601 602 private: 603 mutable std::atomic_uint_fast32_t m_loc = {0}; 604 }; 605 606 template<typename T> 607 struct Dot_Access_AST_Node final : AST_Node_Impl<T> { Dot_Access_AST_Nodechaiscript::eval::Dot_Access_AST_Node608 Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 609 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)), 610 m_fun_name( 611 ((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))? 612 this->children[1]->children[0]->text:this->children[1]->text) { } 613 eval_internalchaiscript::eval::Dot_Access_AST_Node614 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 615 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 616 617 618 Boxed_Value retval = this->children[0]->eval(t_ss); 619 std::vector<Boxed_Value> params{retval}; 620 621 bool has_function_params = false; 622 if (this->children[1]->children.size() > 1) { 623 has_function_params = true; 624 for (const auto &child : this->children[1]->children[1]->children) { 625 params.push_back(child->eval(t_ss)); 626 } 627 } 628 629 fpp.save_params(params); 630 631 try { 632 retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions()); 633 } 634 catch(const exception::dispatch_error &e){ 635 if (e.functions.empty()) 636 { 637 throw exception::eval_error("'" + m_fun_name + "' is not a function."); 638 } else { 639 throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss); 640 } 641 } 642 catch(detail::Return_Value &rv) { 643 retval = std::move(rv.retval); 644 } 645 646 if (this->children[1]->identifier == AST_Node_Type::Array_Call) { 647 try { 648 retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[1]->children[1]->eval(t_ss)}, t_ss.conversions()); 649 } 650 catch(const exception::dispatch_error &e){ 651 throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); 652 } 653 } 654 655 return retval; 656 } 657 658 private: 659 mutable std::atomic_uint_fast32_t m_loc = {0}; 660 mutable std::atomic_uint_fast32_t m_array_loc = {0}; 661 const std::string m_fun_name; 662 }; 663 664 665 template<typename T> 666 struct Lambda_AST_Node final : AST_Node_Impl<T> { Lambda_AST_Nodechaiscript::eval::Lambda_AST_Node667 Lambda_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>(t_ast_node_text, 669 AST_Node_Type::Lambda, 670 std::move(t_loc), 671 std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()), 672 std::make_move_iterator(std::prev(t_children.end()))) 673 ), 674 m_param_names(Arg_List_AST_Node<T>::get_arg_names(*this->children[1])), 675 m_this_capture(has_this_capture(this->children[0]->children)), 676 m_lambda_node(std::move(t_children.back())) 677 { } 678 eval_internalchaiscript::eval::Lambda_AST_Node679 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 680 681 const auto captures = [&]()->std::map<std::string, Boxed_Value>{ 682 std::map<std::string, Boxed_Value> named_captures; 683 for (const auto &capture : this->children[0]->children) { 684 named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss))); 685 } 686 return named_captures; 687 }(); 688 689 const auto numparams = this->children[1]->children.size(); 690 const auto param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss); 691 692 std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss); 693 694 return Boxed_Value( 695 dispatch::make_dynamic_proxy_function( 696 [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures, 697 this_capture = this->m_this_capture] (const std::vector<Boxed_Value> &t_params) 698 { 699 return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture); 700 }, 701 static_cast<int>(numparams), m_lambda_node, param_types 702 ) 703 ); 704 } 705 has_this_capturechaiscript::eval::Lambda_AST_Node706 static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) { 707 return std::any_of(std::begin(children), std::end(children), 708 [](const auto &child){ 709 return child->children[0]->text == "this"; 710 } 711 ); 712 } 713 714 private: 715 const std::vector<std::string> m_param_names; 716 const bool m_this_capture = false; 717 const std::shared_ptr<AST_Node_Impl<T>> m_lambda_node; 718 }; 719 720 template<typename T> 721 struct Scopeless_Block_AST_Node final : AST_Node_Impl<T> { Scopeless_Block_AST_Nodechaiscript::eval::Scopeless_Block_AST_Node722 Scopeless_Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 723 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) { } 724 eval_internalchaiscript::eval::Scopeless_Block_AST_Node725 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 726 const auto num_children = this->children.size(); 727 for (size_t i = 0; i < num_children-1; ++i) { 728 this->children[i]->eval(t_ss); 729 } 730 return this->children.back()->eval(t_ss); 731 } 732 }; 733 734 template<typename T> 735 struct Block_AST_Node final : AST_Node_Impl<T> { Block_AST_Nodechaiscript::eval::Block_AST_Node736 Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 737 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { } 738 eval_internalchaiscript::eval::Block_AST_Node739 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 740 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 741 742 const auto num_children = this->children.size(); 743 for (size_t i = 0; i < num_children-1; ++i) { 744 this->children[i]->eval(t_ss); 745 } 746 return this->children.back()->eval(t_ss); 747 } 748 }; 749 750 template<typename T> 751 struct Def_AST_Node final : AST_Node_Impl<T> { 752 753 std::shared_ptr<AST_Node_Impl<T>> m_body_node; 754 std::shared_ptr<AST_Node_Impl<T>> m_guard_node; 755 Def_AST_Nodechaiscript::eval::Def_AST_Node756 Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 757 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), 758 std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()), 759 std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1))) 760 ), 761 // This apparent use after move is safe because we are only moving out the specific elements we need 762 // on each operation. 763 m_body_node(get_body_node(std::move(t_children))), 764 m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2)) 765 766 { } 767 get_guard_nodechaiscript::eval::Def_AST_Node768 static std::shared_ptr<AST_Node_Impl<T>> get_guard_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec, bool has_guard) 769 { 770 if (has_guard) { 771 return std::move(*std::prev(vec.end(), 2)); 772 } else { 773 return {}; 774 } 775 } 776 get_body_nodechaiscript::eval::Def_AST_Node777 static std::shared_ptr<AST_Node_Impl<T>> get_body_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec) 778 { 779 return std::move(vec.back()); 780 } 781 has_guardchaiscript::eval::Def_AST_Node782 static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset) 783 { 784 if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) { 785 if (t_children.size() > 3 + offset) { 786 return true; 787 } 788 } 789 else { 790 if (t_children.size() > 2 + offset) { 791 return true; 792 } 793 } 794 return false; 795 } 796 eval_internalchaiscript::eval::Def_AST_Node797 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 798 std::vector<std::string> t_param_names; 799 size_t numparams = 0; 800 801 dispatch::Param_Types param_types; 802 803 if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { 804 numparams = this->children[1]->children.size(); 805 t_param_names = Arg_List_AST_Node<T>::get_arg_names(*this->children[1]); 806 param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss); 807 } 808 809 std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss); 810 std::shared_ptr<dispatch::Proxy_Function_Base> guard; 811 if (m_guard_node) { 812 guard = dispatch::make_dynamic_proxy_function( 813 [engine, guardnode = m_guard_node, t_param_names](const std::vector<Boxed_Value> &t_params) 814 { 815 return detail::eval_function(engine, *guardnode, t_param_names, t_params); 816 }, 817 static_cast<int>(numparams), m_guard_node); 818 } 819 820 try { 821 const std::string & l_function_name = this->children[0]->text; 822 t_ss->add( 823 dispatch::make_dynamic_proxy_function( 824 [engine, func_node = m_body_node, t_param_names](const std::vector<Boxed_Value> &t_params) 825 { 826 return detail::eval_function(engine, *func_node, t_param_names, t_params); 827 }, 828 static_cast<int>(numparams), m_body_node, 829 param_types, guard), l_function_name); 830 } catch (const exception::name_conflict_error &e) { 831 throw exception::eval_error("Function redefined '" + e.name() + "'"); 832 } 833 return void_var(); 834 } 835 836 }; 837 838 template<typename T> 839 struct While_AST_Node final : AST_Node_Impl<T> { While_AST_Nodechaiscript::eval::While_AST_Node840 While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 841 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { } 842 eval_internalchaiscript::eval::While_AST_Node843 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 844 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 845 846 try { 847 while (this->get_scoped_bool_condition(*this->children[0], t_ss)) { 848 try { 849 this->children[1]->eval(t_ss); 850 } catch (detail::Continue_Loop &) { 851 // we got a continue exception, which means all of the remaining 852 // loop implementation is skipped and we just need to continue to 853 // the next condition test 854 } 855 } 856 } catch (detail::Break_Loop &) { 857 // loop was broken intentionally 858 } 859 860 return void_var(); 861 } 862 }; 863 864 template<typename T> 865 struct Class_AST_Node final : AST_Node_Impl<T> { Class_AST_Nodechaiscript::eval::Class_AST_Node866 Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 867 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { } 868 eval_internalchaiscript::eval::Class_AST_Node869 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 870 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 871 872 /// \todo do this better 873 // put class name in current scope so it can be looked up by the attrs and methods 874 t_ss.add_object("_current_class_name", const_var(this->children[0]->text)); 875 876 this->children[1]->eval(t_ss); 877 878 return void_var(); 879 } 880 }; 881 882 883 template<typename T> 884 struct If_AST_Node final : AST_Node_Impl<T> { If_AST_Nodechaiscript::eval::If_AST_Node885 If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 886 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) 887 { 888 assert(this->children.size() == 3); 889 } 890 eval_internalchaiscript::eval::If_AST_Node891 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 892 if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) { 893 return this->children[1]->eval(t_ss); 894 } else { 895 return this->children[2]->eval(t_ss); 896 } 897 } 898 }; 899 900 template<typename T> 901 struct Ranged_For_AST_Node final : AST_Node_Impl<T> { Ranged_For_AST_Nodechaiscript::eval::Ranged_For_AST_Node902 Ranged_For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 903 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children)) 904 { assert(this->children.size() == 3); } 905 eval_internalchaiscript::eval::Ranged_For_AST_Node906 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 907 const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){ 908 uint_fast32_t hint = t_hint; 909 auto funs = t_ss->get_function(t_name, hint); 910 if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); } 911 return std::move(funs.second); 912 }; 913 914 const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) { 915 return dispatch::dispatch(*t_funcs, {t_param}, t_ss.conversions()); 916 }; 917 918 919 const std::string &loop_var_name = this->children[0]->text; 920 Boxed_Value range_expression_result = this->children[1]->eval(t_ss); 921 922 923 const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing){ 924 try { 925 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 926 Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var()); 927 for (auto loop_var : ranged_thing) { 928 obj = Boxed_Value(std::move(loop_var)); 929 try { 930 this->children[2]->eval(t_ss); 931 } catch (detail::Continue_Loop &) { 932 } 933 } 934 } catch (detail::Break_Loop &) { 935 // loop broken 936 } 937 return void_var(); 938 }; 939 940 if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::vector<Boxed_Value>))) { 941 return do_loop(boxed_cast<const std::vector<Boxed_Value> &>(range_expression_result)); 942 } else if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::map<std::string, Boxed_Value>))) { 943 return do_loop(boxed_cast<const std::map<std::string, Boxed_Value> &>(range_expression_result)); 944 } else { 945 const auto range_funcs = get_function("range", m_range_loc); 946 const auto empty_funcs = get_function("empty", m_empty_loc); 947 const auto front_funcs = get_function("front", m_front_loc); 948 const auto pop_front_funcs = get_function("pop_front", m_pop_front_loc); 949 950 try { 951 const auto range_obj = call_function(range_funcs, range_expression_result); 952 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 953 Boxed_Value &obj = t_ss.add_get_object(loop_var_name, void_var()); 954 while (!boxed_cast<bool>(call_function(empty_funcs, range_obj))) { 955 obj = call_function(front_funcs, range_obj); 956 try { 957 this->children[2]->eval(t_ss); 958 } catch (detail::Continue_Loop &) { 959 } 960 call_function(pop_front_funcs, range_obj); 961 } 962 } catch (detail::Break_Loop &) { 963 // loop broken 964 } 965 return void_var(); 966 } 967 968 } 969 970 private: 971 mutable std::atomic_uint_fast32_t m_range_loc = {0}; 972 mutable std::atomic_uint_fast32_t m_empty_loc = {0}; 973 mutable std::atomic_uint_fast32_t m_front_loc = {0}; 974 mutable std::atomic_uint_fast32_t m_pop_front_loc = {0}; 975 }; 976 977 978 template<typename T> 979 struct For_AST_Node final : AST_Node_Impl<T> { For_AST_Nodechaiscript::eval::For_AST_Node980 For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 981 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children)) 982 { assert(this->children.size() == 4); } 983 eval_internalchaiscript::eval::For_AST_Node984 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 985 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 986 987 try { 988 for ( 989 this->children[0]->eval(t_ss); 990 this->get_scoped_bool_condition(*this->children[1], t_ss); 991 this->children[2]->eval(t_ss) 992 ) { 993 try { 994 // Body of Loop 995 this->children[3]->eval(t_ss); 996 } catch (detail::Continue_Loop &) { 997 // we got a continue exception, which means all of the remaining 998 // loop implementation is skipped and we just need to continue to 999 // the next iteration step 1000 } 1001 } 1002 } catch (detail::Break_Loop &) { 1003 // loop broken 1004 } 1005 1006 return void_var(); 1007 } 1008 1009 }; 1010 1011 template<typename T> 1012 struct Switch_AST_Node final : AST_Node_Impl<T> { Switch_AST_Nodechaiscript::eval::Switch_AST_Node1013 Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1014 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { } 1015 eval_internalchaiscript::eval::Switch_AST_Node1016 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 1017 bool breaking = false; 1018 size_t currentCase = 1; 1019 bool hasMatched = false; 1020 1021 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 1022 1023 Boxed_Value match_value(this->children[0]->eval(t_ss)); 1024 1025 while (!breaking && (currentCase < this->children.size())) { 1026 try { 1027 if (this->children[currentCase]->identifier == AST_Node_Type::Case) { 1028 //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. 1029 try { 1030 if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) { 1031 this->children[currentCase]->eval(t_ss); 1032 hasMatched = true; 1033 } 1034 } 1035 catch (const exception::bad_boxed_cast &) { 1036 throw exception::eval_error("Internal error: case guard evaluation not boolean"); 1037 } 1038 } 1039 else if (this->children[currentCase]->identifier == AST_Node_Type::Default) { 1040 this->children[currentCase]->eval(t_ss); 1041 hasMatched = true; 1042 } 1043 } 1044 catch (detail::Break_Loop &) { 1045 breaking = true; 1046 } 1047 ++currentCase; 1048 } 1049 return void_var(); 1050 } 1051 1052 mutable std::atomic_uint_fast32_t m_loc = {0}; 1053 }; 1054 1055 template<typename T> 1056 struct Case_AST_Node final : AST_Node_Impl<T> { Case_AST_Nodechaiscript::eval::Case_AST_Node1057 Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1058 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children)) 1059 { assert(this->children.size() == 2); /* how many children does it have? */ } 1060 eval_internalchaiscript::eval::Case_AST_Node1061 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 1062 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 1063 1064 this->children[1]->eval(t_ss); 1065 1066 return void_var(); 1067 } 1068 }; 1069 1070 template<typename T> 1071 struct Default_AST_Node final : AST_Node_Impl<T> { Default_AST_Nodechaiscript::eval::Default_AST_Node1072 Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1073 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children)) 1074 { assert(this->children.size() == 1); } 1075 eval_internalchaiscript::eval::Default_AST_Node1076 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 1077 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 1078 1079 this->children[0]->eval(t_ss); 1080 1081 return void_var(); 1082 } 1083 }; 1084 1085 1086 template<typename T> 1087 struct Inline_Array_AST_Node final : AST_Node_Impl<T> { Inline_Array_AST_Nodechaiscript::eval::Inline_Array_AST_Node1088 Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1089 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { } 1090 eval_internalchaiscript::eval::Inline_Array_AST_Node1091 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 1092 try { 1093 std::vector<Boxed_Value> vec; 1094 if (!this->children.empty()) { 1095 vec.reserve(this->children[0]->children.size()); 1096 for (const auto &child : this->children[0]->children) { 1097 vec.push_back(detail::clone_if_necessary(child->eval(t_ss), m_loc, t_ss)); 1098 } 1099 } 1100 return const_var(std::move(vec)); 1101 } 1102 catch (const exception::dispatch_error &) { 1103 throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements"); 1104 } 1105 } 1106 1107 private: 1108 mutable std::atomic_uint_fast32_t m_loc = {0}; 1109 }; 1110 1111 template<typename T> 1112 struct Inline_Map_AST_Node final : AST_Node_Impl<T> { Inline_Map_AST_Nodechaiscript::eval::Inline_Map_AST_Node1113 Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1114 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { } 1115 eval_internalchaiscript::eval::Inline_Map_AST_Node1116 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 1117 { 1118 try { 1119 std::map<std::string, Boxed_Value> retval; 1120 1121 for (const auto &child : this->children[0]->children) { 1122 retval.insert(std::make_pair(t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss)), 1123 detail::clone_if_necessary(child->children[1]->eval(t_ss), m_loc, t_ss))); 1124 } 1125 1126 return const_var(std::move(retval)); 1127 } 1128 catch (const exception::dispatch_error &e) { 1129 throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss); 1130 } 1131 } 1132 1133 private: 1134 mutable std::atomic_uint_fast32_t m_loc = {0}; 1135 }; 1136 1137 template<typename T> 1138 struct Return_AST_Node final : AST_Node_Impl<T> { Return_AST_Nodechaiscript::eval::Return_AST_Node1139 Return_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::Return, std::move(t_loc), std::move(t_children)) { } 1141 eval_internalchaiscript::eval::Return_AST_Node1142 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 1143 if (!this->children.empty()) { 1144 throw detail::Return_Value(this->children[0]->eval(t_ss)); 1145 } 1146 else { 1147 throw detail::Return_Value(void_var()); 1148 } 1149 } 1150 }; 1151 1152 template<typename T> 1153 struct File_AST_Node final : AST_Node_Impl<T> { File_AST_Nodechaiscript::eval::File_AST_Node1154 File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1155 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { } 1156 eval_internalchaiscript::eval::File_AST_Node1157 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 1158 try { 1159 const auto num_children = this->children.size(); 1160 1161 if (num_children > 0) { 1162 for (size_t i = 0; i < num_children-1; ++i) { 1163 this->children[i]->eval(t_ss); 1164 } 1165 return this->children.back()->eval(t_ss); 1166 } else { 1167 return void_var(); 1168 } 1169 } catch (const detail::Continue_Loop &) { 1170 throw exception::eval_error("Unexpected `continue` statement outside of a loop"); 1171 } catch (const detail::Break_Loop &) { 1172 throw exception::eval_error("Unexpected `break` statement outside of a loop"); 1173 } 1174 } 1175 }; 1176 1177 template<typename T> 1178 struct Reference_AST_Node final : AST_Node_Impl<T> { Reference_AST_Nodechaiscript::eval::Reference_AST_Node1179 Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1180 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children)) 1181 { assert(this->children.size() == 1); } 1182 eval_internalchaiscript::eval::Reference_AST_Node1183 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 1184 Boxed_Value bv; 1185 t_ss.add_object(this->children[0]->text, bv); 1186 return bv; 1187 } 1188 }; 1189 1190 template<typename T> 1191 struct Prefix_AST_Node final : AST_Node_Impl<T> { Prefix_AST_Nodechaiscript::eval::Prefix_AST_Node1192 Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1193 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)), 1194 m_oper(Operators::to_operator(this->text, true)) 1195 { } 1196 eval_internalchaiscript::eval::Prefix_AST_Node1197 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 1198 Boxed_Value bv(this->children[0]->eval(t_ss)); 1199 1200 try { 1201 // short circuit arithmetic operations 1202 if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic()) 1203 { 1204 return Boxed_Number::do_oper(m_oper, bv); 1205 } else { 1206 chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); 1207 fpp.save_params({bv}); 1208 return t_ss->call_function(this->text, m_loc, {std::move(bv)}, t_ss.conversions()); 1209 } 1210 } catch (const exception::dispatch_error &e) { 1211 throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss); 1212 } 1213 } 1214 1215 private: 1216 Operators::Opers m_oper = Operators::Opers::invalid; 1217 mutable std::atomic_uint_fast32_t m_loc = {0}; 1218 }; 1219 1220 template<typename T> 1221 struct Break_AST_Node final : AST_Node_Impl<T> { Break_AST_Nodechaiscript::eval::Break_AST_Node1222 Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1223 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { } 1224 eval_internalchaiscript::eval::Break_AST_Node1225 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ 1226 throw detail::Break_Loop(); 1227 } 1228 }; 1229 1230 template<typename T> 1231 struct Continue_AST_Node final : AST_Node_Impl<T> { Continue_AST_Nodechaiscript::eval::Continue_AST_Node1232 Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1233 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { } 1234 eval_internalchaiscript::eval::Continue_AST_Node1235 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ 1236 throw detail::Continue_Loop(); 1237 } 1238 }; 1239 1240 template<typename T> 1241 struct Noop_AST_Node final : AST_Node_Impl<T> { Noop_AST_Nodechaiscript::eval::Noop_AST_Node1242 Noop_AST_Node() : 1243 AST_Node_Impl<T>("", AST_Node_Type::Noop, Parse_Location()) 1244 { } 1245 eval_internalchaiscript::eval::Noop_AST_Node1246 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ 1247 // It's a no-op, that evaluates to "void" 1248 return val; 1249 } 1250 1251 Boxed_Value val = void_var(); 1252 }; 1253 1254 template<typename T> 1255 struct Map_Pair_AST_Node final : AST_Node_Impl<T> { Map_Pair_AST_Nodechaiscript::eval::Map_Pair_AST_Node1256 Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1257 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { } 1258 }; 1259 1260 template<typename T> 1261 struct Value_Range_AST_Node final : AST_Node_Impl<T> { Value_Range_AST_Nodechaiscript::eval::Value_Range_AST_Node1262 Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1263 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { } 1264 }; 1265 1266 template<typename T> 1267 struct Inline_Range_AST_Node final : AST_Node_Impl<T> { Inline_Range_AST_Nodechaiscript::eval::Inline_Range_AST_Node1268 Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1269 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { } 1270 eval_internalchaiscript::eval::Inline_Range_AST_Node1271 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 1272 try { 1273 auto oper1 = this->children[0]->children[0]->children[0]->eval(t_ss); 1274 auto oper2 = this->children[0]->children[0]->children[1]->eval(t_ss); 1275 return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions()); 1276 } 1277 catch (const exception::dispatch_error &e) { 1278 throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); 1279 } 1280 } 1281 1282 private: 1283 mutable std::atomic_uint_fast32_t m_loc = {0}; 1284 }; 1285 1286 template<typename T> 1287 struct Try_AST_Node final : AST_Node_Impl<T> { Try_AST_Nodechaiscript::eval::Try_AST_Node1288 Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1289 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { } 1290 handle_exceptionchaiscript::eval::Try_AST_Node1291 Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const 1292 { 1293 Boxed_Value retval; 1294 1295 size_t end_point = this->children.size(); 1296 if (this->children.back()->identifier == AST_Node_Type::Finally) { 1297 assert(end_point > 0); 1298 end_point = this->children.size() - 1; 1299 } 1300 for (size_t i = 1; i < end_point; ++i) { 1301 chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss); 1302 auto &catch_block = *this->children[i]; 1303 1304 if (catch_block.children.size() == 1) { 1305 //No variable capture, no guards 1306 retval = catch_block.children[0]->eval(t_ss); 1307 break; 1308 } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) { 1309 const auto name = Arg_List_AST_Node<T>::get_arg_name(*catch_block.children[0]); 1310 1311 if (dispatch::Param_Types( 1312 std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)} 1313 ).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first) 1314 { 1315 t_ss.add_object(name, t_except); 1316 1317 if (catch_block.children.size() == 2) { 1318 //Variable capture, no guards 1319 retval = catch_block.children[1]->eval(t_ss); 1320 break; 1321 } 1322 else if (catch_block.children.size() == 3) { 1323 //Variable capture, guards 1324 1325 bool guard = false; 1326 try { 1327 guard = boxed_cast<bool>(catch_block.children[1]->eval(t_ss)); 1328 } catch (const exception::bad_boxed_cast &) { 1329 if (this->children.back()->identifier == AST_Node_Type::Finally) { 1330 this->children.back()->children[0]->eval(t_ss); 1331 } 1332 throw exception::eval_error("Guard condition not boolean"); 1333 } 1334 if (guard) { 1335 retval = catch_block.children[2]->eval(t_ss); 1336 break; 1337 } 1338 } 1339 } 1340 } 1341 else { 1342 if (this->children.back()->identifier == AST_Node_Type::Finally) { 1343 this->children.back()->children[0]->eval(t_ss); 1344 } 1345 throw exception::eval_error("Internal error: catch block size unrecognized"); 1346 } 1347 } 1348 1349 return retval; 1350 } 1351 eval_internalchaiscript::eval::Try_AST_Node1352 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { 1353 Boxed_Value retval; 1354 1355 chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); 1356 1357 1358 try { 1359 retval = this->children[0]->eval(t_ss); 1360 } 1361 catch (const exception::eval_error &e) { 1362 retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); 1363 } 1364 catch (const std::runtime_error &e) { 1365 retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); 1366 } 1367 catch (const std::out_of_range &e) { 1368 retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); 1369 } 1370 catch (const std::exception &e) { 1371 retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); 1372 } 1373 catch (Boxed_Value &e) { 1374 retval = handle_exception(t_ss, e); 1375 } 1376 catch (...) { 1377 if (this->children.back()->identifier == AST_Node_Type::Finally) { 1378 this->children.back()->children[0]->eval(t_ss); 1379 } 1380 throw; 1381 } 1382 1383 1384 if (this->children.back()->identifier == AST_Node_Type::Finally) { 1385 retval = this->children.back()->children[0]->eval(t_ss); 1386 } 1387 1388 return retval; 1389 } 1390 1391 }; 1392 1393 template<typename T> 1394 struct Catch_AST_Node final : AST_Node_Impl<T> { Catch_AST_Nodechaiscript::eval::Catch_AST_Node1395 Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1396 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { } 1397 }; 1398 1399 template<typename T> 1400 struct Finally_AST_Node final : AST_Node_Impl<T> { Finally_AST_Nodechaiscript::eval::Finally_AST_Node1401 Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1402 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { } 1403 }; 1404 1405 template<typename T> 1406 struct Method_AST_Node final : AST_Node_Impl<T> { 1407 std::shared_ptr<AST_Node_Impl<T>> m_body_node; 1408 std::shared_ptr<AST_Node_Impl<T>> m_guard_node; 1409 Method_AST_Nodechaiscript::eval::Method_AST_Node1410 Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1411 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), 1412 std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()), 1413 std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1))) 1414 ), 1415 m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))), 1416 m_guard_node(Def_AST_Node<T>::get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2)) 1417 { 1418 } 1419 eval_internalchaiscript::eval::Method_AST_Node1420 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ 1421 1422 AST_Node_Impl_Ptr<T> guardnode; 1423 1424 const std::string & class_name = this->children[0]->text; 1425 1426 //The first param of a method is always the implied this ptr. 1427 std::vector<std::string> t_param_names{"this"}; 1428 dispatch::Param_Types param_types; 1429 1430 if ((this->children.size() > 2) 1431 && (this->children[2]->identifier == AST_Node_Type::Arg_List)) { 1432 auto args = Arg_List_AST_Node<T>::get_arg_names(*this->children[2]); 1433 t_param_names.insert(t_param_names.end(), args.begin(), args.end()); 1434 param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[2], t_ss); 1435 } 1436 1437 const size_t numparams = t_param_names.size(); 1438 1439 std::shared_ptr<dispatch::Proxy_Function_Base> guard; 1440 std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss); 1441 if (m_guard_node) { 1442 guard = dispatch::make_dynamic_proxy_function( 1443 [engine, t_param_names, guardnode = m_guard_node](const std::vector<Boxed_Value> &t_params) { 1444 return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params); 1445 }, 1446 static_cast<int>(numparams), m_guard_node); 1447 } 1448 1449 try { 1450 const std::string & function_name = this->children[1]->text; 1451 1452 if (function_name == class_name) { 1453 param_types.push_front(class_name, Type_Info()); 1454 1455 t_ss->add( 1456 std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, 1457 dispatch::make_dynamic_proxy_function( 1458 [engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) { 1459 return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); 1460 }, 1461 static_cast<int>(numparams), m_body_node, param_types, guard 1462 ) 1463 ), 1464 function_name); 1465 1466 } else { 1467 // if the type is unknown, then this generates a function that looks up the type 1468 // at runtime. Defining the type first before this is called is better 1469 auto type = t_ss->get_type(class_name, false); 1470 param_types.push_front(class_name, type); 1471 1472 t_ss->add( 1473 std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name, 1474 dispatch::make_dynamic_proxy_function( 1475 [engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) { 1476 return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); 1477 }, 1478 static_cast<int>(numparams), m_body_node, param_types, guard), type), 1479 function_name); 1480 } 1481 } catch (const exception::name_conflict_error &e) { 1482 throw exception::eval_error("Method redefined '" + e.name() + "'"); 1483 } 1484 return void_var(); 1485 } 1486 1487 }; 1488 1489 template<typename T> 1490 struct Attr_Decl_AST_Node final : AST_Node_Impl<T> { Attr_Decl_AST_Nodechaiscript::eval::Attr_Decl_AST_Node1491 Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1492 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { } 1493 eval_internalchaiscript::eval::Attr_Decl_AST_Node1494 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 1495 { 1496 std::string class_name = this->children[0]->text; 1497 1498 try { 1499 std::string attr_name = this->children[1]->text; 1500 1501 t_ss->add( 1502 std::make_shared<dispatch::detail::Dynamic_Object_Function>( 1503 std::move(class_name), 1504 fun([attr_name](dispatch::Dynamic_Object &t_obj) { 1505 return t_obj.get_attr(attr_name); 1506 }), 1507 true 1508 1509 ), this->children[1]->text); 1510 } catch (const exception::name_conflict_error &e) { 1511 throw exception::eval_error("Attribute redefined '" + e.name() + "'"); 1512 } 1513 return void_var(); 1514 } 1515 1516 }; 1517 1518 1519 template<typename T> 1520 struct Logical_And_AST_Node final : AST_Node_Impl<T> { Logical_And_AST_Nodechaiscript::eval::Logical_And_AST_Node1521 Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1522 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children)) 1523 { assert(this->children.size() == 2); } 1524 eval_internalchaiscript::eval::Logical_And_AST_Node1525 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 1526 { 1527 return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss) 1528 && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss)); 1529 } 1530 1531 }; 1532 1533 template<typename T> 1534 struct Logical_Or_AST_Node final : AST_Node_Impl<T> { Logical_Or_AST_Nodechaiscript::eval::Logical_Or_AST_Node1535 Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) : 1536 AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) 1537 { assert(this->children.size() == 2); } 1538 eval_internalchaiscript::eval::Logical_Or_AST_Node1539 Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 1540 { 1541 return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss) 1542 || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss)); 1543 } 1544 }; 1545 } 1546 1547 1548 } 1549 #endif /* CHAISCRIPT_EVAL_HPP_ */ 1550 1551