10 #ifndef CHAISCRIPT_EVAL_HPP_ 11 #define CHAISCRIPT_EVAL_HPP_ 23 #include "../chaiscript_defines.hpp" 24 #include "../dispatchkit/boxed_cast.hpp" 25 #include "../dispatchkit/boxed_number.hpp" 26 #include "../dispatchkit/boxed_value.hpp" 27 #include "../dispatchkit/dispatchkit.hpp" 28 #include "../dispatchkit/dynamic_object_detail.hpp" 29 #include "../dispatchkit/proxy_functions.hpp" 30 #include "../dispatchkit/proxy_functions_detail.hpp" 31 #include "../dispatchkit/register_function.hpp" 32 #include "../dispatchkit/type_info.hpp" 33 #include "chaiscript_algebraic.hpp" 34 #include "chaiscript_common.hpp" 47 using AST_Node_Impl_Ptr =
typename std::unique_ptr<AST_Node_Impl<T>>;
54 const std::vector<std::string> &t_param_names,
56 const std::map<std::string, Boxed_Value> *t_locals =
nullptr,
57 bool has_this_capture =
false) {
61 if (
auto &stack = t_ss.
get_stack_data(state.stack_holder()).back(); !stack.empty() && stack.back().first ==
"__this") {
62 return &stack.back().second;
63 }
else if (!t_vals.empty()) {
71 if (thisobj && !has_this_capture) {
72 state.add_object(
"this", *thisobj);
76 for (
const auto &[name, value] : *t_locals) {
77 state.add_object(name, value);
81 for (
size_t i = 0; i < t_param_names.size(); ++i) {
82 if (t_param_names[i] !=
"this") {
83 state.add_object(t_param_names[i], t_vals[i]);
88 return t_node.eval(state);
90 return std::move(rv.retval);
95 if (!incoming.is_return_value()) {
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 if (incoming.get_type_info().bare_equal_type_info(
typeid(std::string))) {
101 return Boxed_Value(*static_cast<const std::string *>(incoming.get_const_ptr()));
103 std::array<Boxed_Value, 1> params{std::move(incoming)};
104 return t_ss->call_function(
"clone", t_loc,
Function_Params{params}, t_ss.conversions());
107 incoming.reset_return_value();
118 std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>())
119 :
AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc))
120 , children(std::move(t_children)) {
125 return get_bool_condition(node.eval(t_ss), t_ss);
128 std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
129 std::vector<std::reference_wrapper<AST_Node>> retval;
130 retval.reserve(children.size());
131 for (
auto &child : children) {
132 retval.emplace_back(*child);
141 return eval_internal(t_e);
143 ee.call_stack.push_back(*
this);
148 std::vector<AST_Node_Impl_Ptr<T>> children;
152 throw std::runtime_error(
"Undispatched ast_node (internal error)");
159 std::vector<AST_Node_Impl_Ptr<T>> t_children,
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)) {
169 AST_Node_Impl_Ptr<T> m_original_node;
175 :
AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children))
176 , m_oper(Operators::to_operator(t_oper))
177 , m_rhs(std::move(t_rhs)) {
181 return do_oper(t_ss, this->text, this->children[0]->eval(t_ss));
187 if (t_lhs.get_type_info().is_arithmetic()) {
190 return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs);
198 std::array<Boxed_Value, 2> params{t_lhs, m_rhs};
200 return t_ss->call_function(t_oper_string, m_loc,
Function_Params{params}, t_ss.conversions());
203 throw exception::eval_error(
"Can not find appropriate '" + t_oper_string +
"' operator.", e.parameters, e.functions,
false, *t_ss);
208 Operators::Opers m_oper;
210 mutable std::atomic_uint_fast32_t m_loc = {0};
216 :
AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children))
217 , m_oper(Operators::to_operator(t_oper)) {
221 auto lhs = this->children[0]->eval(t_ss);
222 auto rhs = this->children[1]->eval(t_ss);
223 return do_oper(t_ss, m_oper, this->text, lhs, rhs);
228 Operators::Opers t_oper,
229 const std::string &t_oper_string,
233 if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic()) {
236 return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
244 std::array<Boxed_Value, 2> params{t_lhs, t_rhs};
246 return t_ss->call_function(t_oper_string, m_loc,
Function_Params(params), t_ss.conversions());
249 throw exception::eval_error(
"Can not find appropriate '" + t_oper_string +
"' operator.", e.parameters, e.functions,
false, *t_ss);
254 Operators::Opers m_oper;
255 mutable std::atomic_uint_fast32_t m_loc = {0};
261 :
AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc))
262 , m_value(std::move(t_value)) {
267 , m_value(std::move(t_value)) {
283 return t_ss.get_object(this->text, m_loc);
284 }
catch (std::exception &) {
290 mutable std::atomic_uint_fast32_t m_loc = {0};
296 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) {
297 assert(!this->children.empty());
300 template<
bool Save_Params>
304 std::vector<Boxed_Value> params;
306 params.reserve(this->children[1]->children.size());
307 for (
const auto &child : this->children[1]->children) {
308 params.push_back(child->eval(t_ss));
320 throw exception::eval_error(std::string(e.what()) +
" with function '" + this->children[0]->text +
"'",
330 throw exception::eval_error(
"Error calling function '" + this->children[0]->text +
"'", params, make_vector(f),
false, *t_ss);
332 throw exception::eval_error(
"'" + this->children[0]->pretty_print() +
"' does not evaluate to a function.");
335 throw exception::eval_error(std::string(e.what()) +
" with function '" + this->children[0]->text +
"'");
337 throw exception::eval_error(std::string(e.what()) +
" with function '" + this->children[0]->text +
"'");
353 return this->
template do_eval_internal<false>(t_ss);
360 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) {
367 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) {
371 if (t_node.children.empty()) {
373 }
else if (t_node.children.size() == 1) {
374 return t_node.children[0]->text;
376 return t_node.children[1]->text;
380 static std::vector<std::string> get_arg_names(
const AST_Node_Impl<T> &t_node) {
381 std::vector<std::string> retval;
383 for (
const auto &node : t_node.children) {
384 retval.push_back(get_arg_name(*node));
391 if (t_node.children.size() < 2) {
394 return {t_node.children[0]->text, t_ss->
get_type(t_node.children[0]->text,
false)};
399 std::vector<std::pair<std::string, Type_Info>> retval;
401 for (
const auto &child : t_node.children) {
402 retval.push_back(get_arg_type(*child, t_ss));
412 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children))
413 , m_oper(Operators::to_operator(this->text)) {
414 assert(this->children.size() == 2);
420 auto params = [&]() {
425 auto rhs = this->children[1]->eval(t_ss);
426 auto lhs = this->children[0]->eval(t_ss);
427 std::array<Boxed_Value, 2> p{std::move(lhs), std::move(rhs)};
431 if (params[0].is_return_value()) {
433 }
else if (params[0].is_const()) {
437 if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() && params[1].get_type_info().is_arithmetic()) {
439 return Boxed_Number::do_oper(m_oper, params[0], params[1]);
440 }
catch (
const std::exception &) {
443 }
else if (m_oper == Operators::Opers::assign) {
445 if (params[0].is_undef()) {
446 if (!this->children.empty()
447 && ((this->children[0]->identifier == AST_Node_Type::Reference)
448 || (!this->children[0]->children.empty() && this->children[0]->children[0]->identifier == AST_Node_Type::Reference)))
453 params[0].assign(params[1]);
454 params[0].reset_return_value();
457 params[1] = detail::clone_if_necessary(std::move(params[1]), m_clone_loc, t_ss);
462 return t_ss->call_function(this->text, m_loc,
Function_Params{params}, t_ss.conversions());
464 throw exception::eval_error(
"Unable to find appropriate'" + this->text +
"' operator.", e.parameters, e.functions,
false, *t_ss);
473 }
else if (this->text ==
":=") {
475 params[0].assign(params[1]);
476 params[0].reset_return_value();
482 return t_ss->call_function(this->text, m_loc,
Function_Params{params}, t_ss.conversions());
484 throw exception::eval_error(
"Unable to find appropriate'" + this->text +
"' operator.", e.parameters, e.functions,
false, *t_ss);
492 Operators::Opers m_oper;
493 mutable std::atomic_uint_fast32_t m_loc = {0};
494 mutable std::atomic_uint_fast32_t m_clone_loc = {0};
500 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) {
504 const std::string &idname = (this->children[0]->identifier == AST_Node_Type::Reference) ? this->children[0]->children[0]->text : this->children[0]->text;
513 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) {
517 const std::string &idname = this->children[0]->text;
521 t_ss.add_object(idname, bv);
532 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Assign_Decl, std::move(t_loc), std::move(t_children)) {
536 const std::string &idname = this->children[0]->text;
539 Boxed_Value bv(detail::clone_if_necessary(this->children[1]->eval(t_ss), m_loc, t_ss));
540 bv.reset_return_value();
541 t_ss.add_object(idname, bv);
549 mutable std::atomic_uint_fast32_t m_loc = {0};
555 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) {
561 std::array<Boxed_Value, 2> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
565 return t_ss->call_function(
"[]", m_loc,
Function_Params{params}, t_ss.conversions());
567 throw exception::eval_error(
"Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions,
false, *t_ss);
572 mutable std::atomic_uint_fast32_t m_loc = {0};
578 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children))
579 , m_fun_name(((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))
580 ? this->children[1]->children[0]->text
581 : this->children[1]->text) {
587 Boxed_Value retval = this->children[0]->eval(t_ss);
588 auto params = make_vector(retval);
590 bool has_function_params =
false;
591 if (this->children[1]->children.size() > 1) {
592 has_function_params =
true;
593 for (
const auto &child : this->children[1]->children[1]->children) {
594 params.push_back(child->eval(t_ss));
601 retval = t_ss->call_member(m_fun_name, m_loc,
Function_Params{params}, has_function_params, t_ss.conversions());
603 if (e.functions.empty()) {
606 throw exception::eval_error(std::string(e.what()) +
" for function '" + m_fun_name +
"'", e.parameters, e.functions,
true, *t_ss);
609 retval = std::move(rv.retval);
612 if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
614 std::array<Boxed_Value, 2> p{retval, this->children[1]->children[1]->eval(t_ss)};
615 retval = t_ss->call_function(
"[]", m_array_loc,
Function_Params{p}, t_ss.conversions());
617 throw exception::eval_error(
"Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions,
true, *t_ss);
625 mutable std::atomic_uint_fast32_t m_loc = {0};
626 mutable std::atomic_uint_fast32_t m_array_loc = {0};
627 const std::string m_fun_name;
634 AST_Node_Type::Lambda,
636 std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
637 std::make_move_iterator(std::prev(t_children.end()))))
639 , m_this_capture(has_this_capture(this->children[0]->children))
640 , m_lambda_node(std::move(t_children.back())) {
644 const auto captures = [&]() -> std::map<std::string, Boxed_Value> {
645 std::map<std::string, Boxed_Value> named_captures;
646 for (
const auto &capture : this->children[0]->children) {
647 named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
649 return named_captures;
652 const auto numparams = this->children[1]->children.size();
655 std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
657 return Boxed_Value(dispatch::make_dynamic_proxy_function(
658 [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures, this_capture = this->m_this_capture](
660 return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture);
662 static_cast<int>(numparams),
667 static bool has_this_capture(
const std::vector<AST_Node_Impl_Ptr<T>> &t_children) noexcept {
668 return std::any_of(std::begin(t_children), std::end(t_children), [](
const auto &child) {
return child->children[0]->text ==
"this"; });
672 const std::vector<std::string> m_param_names;
673 const bool m_this_capture =
false;
674 const std::shared_ptr<AST_Node_Impl<T>> m_lambda_node;
680 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) {
684 const auto num_children = this->children.size();
685 for (
size_t i = 0; i < num_children - 1; ++i) {
686 this->children[i]->eval(t_ss);
688 return this->children.back()->eval(t_ss);
695 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) {
701 const auto num_children = this->children.size();
702 for (
size_t i = 0; i < num_children - 1; ++i) {
703 this->children[i]->eval(t_ss);
705 return this->children.back()->eval(t_ss);
711 std::shared_ptr<AST_Node_Impl<T>> m_body_node;
712 std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
718 std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
719 std::make_move_iterator(
720 std::prev(t_children.end(), has_guard(t_children, 1) ? 2 : 1))))
724 m_body_node(get_body_node(std::move(t_children)))
725 , m_guard_node(get_guard_node(std::move(t_children), t_children.size() - this->children.size() == 2))
730 static std::shared_ptr<AST_Node_Impl<T>> get_guard_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec,
bool has_guard) {
732 return std::move(*std::prev(vec.end(), 2));
738 static std::shared_ptr<AST_Node_Impl<T>> get_body_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec) {
return std::move(vec.back()); }
740 static bool has_guard(
const std::vector<AST_Node_Impl_Ptr<T>> &t_children,
const std::size_t offset) noexcept {
741 if ((t_children.size() > 2 + offset) && (t_children[1 + offset]->identifier == AST_Node_Type::Arg_List)) {
742 if (t_children.size() > 3 + offset) {
746 if (t_children.size() > 2 + offset) {
754 std::vector<std::string> t_param_names;
755 size_t numparams = 0;
759 if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
760 numparams = this->children[1]->children.size();
765 std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
766 std::shared_ptr<dispatch::Proxy_Function_Base> guard;
768 guard = dispatch::make_dynamic_proxy_function(
769 [engine, guardnode = m_guard_node, t_param_names](
const Function_Params &t_params) {
770 return detail::eval_function(engine, *guardnode, t_param_names, t_params);
772 static_cast<int>(numparams),
777 const std::string &l_function_name = this->children[0]->text;
778 t_ss->
add(dispatch::make_dynamic_proxy_function(
779 [engine, func_node = m_body_node, t_param_names](
const Function_Params &t_params) {
780 return detail::eval_function(engine, *func_node, t_param_names, t_params);
782 static_cast<int>(numparams),
797 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) {
804 while (this->get_scoped_bool_condition(*this->children[0], t_ss)) {
806 this->children[1]->eval(t_ss);
824 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) {
832 t_ss.add_object(
"_current_class_name",
const_var(this->children[0]->text));
834 this->children[1]->eval(t_ss);
843 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) {
844 assert(this->children.size() == 3);
848 if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) {
849 return this->children[1]->eval(t_ss);
851 return this->children[2]->eval(t_ss);
859 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children)) {
860 assert(this->children.size() == 3);
864 const auto get_function = [&t_ss](
const std::string &t_name,
auto &t_hint) {
865 uint_fast32_t hint = t_hint;
866 auto [funs_loc, funs] = t_ss->
get_function(t_name, hint);
867 if (funs_loc != hint) {
868 t_hint = uint_fast32_t(funs_loc);
870 return std::move(funs);
873 const auto call_function = [&t_ss](
const auto &t_funcs,
const Boxed_Value &t_param) {
877 const std::string &loop_var_name = this->children[0]->text;
878 Boxed_Value range_expression_result = this->children[1]->eval(t_ss);
880 const auto do_loop = [&loop_var_name, &t_ss,
this](
const auto &ranged_thing) {
882 for (
auto &&loop_var : ranged_thing) {
887 if (!std::is_same<std::decay_t<decltype(loop_var)>,
Boxed_Value>::value) {
888 t_ss.add_get_object(loop_var_name,
Boxed_Value(std::ref(loop_var)));
890 t_ss.add_get_object(loop_var_name,
Boxed_Value(loop_var));
893 this->children[2]->eval(t_ss);
903 if (range_expression_result.get_type_info().bare_equal_type_info(
typeid(std::vector<Boxed_Value>))) {
904 return do_loop(
boxed_cast<
const std::vector<Boxed_Value> &>(range_expression_result));
905 }
else if (range_expression_result.get_type_info().bare_equal_type_info(
typeid(std::map<std::string, Boxed_Value>))) {
906 return do_loop(
boxed_cast<
const std::map<std::string, Boxed_Value> &>(range_expression_result));
908 const auto range_funcs = get_function(
"range", m_range_loc);
909 const auto empty_funcs = get_function(
"empty", m_empty_loc);
910 const auto front_funcs = get_function(
"front", m_front_loc);
911 const auto pop_front_funcs = get_function(
"pop_front", m_pop_front_loc);
914 const auto range_obj = call_function(range_funcs, range_expression_result);
915 while (!boxed_cast<bool>(call_function(empty_funcs, range_obj))) {
917 t_ss.add_get_object(loop_var_name, call_function(front_funcs, range_obj));
919 this->children[2]->eval(t_ss);
923 call_function(pop_front_funcs, range_obj);
933 mutable std::atomic_uint_fast32_t m_range_loc = {0};
934 mutable std::atomic_uint_fast32_t m_empty_loc = {0};
935 mutable std::atomic_uint_fast32_t m_front_loc = {0};
936 mutable std::atomic_uint_fast32_t m_pop_front_loc = {0};
942 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children)) {
943 assert(this->children.size() == 4);
950 for (this->children[0]->eval(t_ss); this->get_scoped_bool_condition(*this->children[1], t_ss); this->children[2]->eval(t_ss)) {
953 this->children[3]->eval(t_ss);
971 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) {
975 bool breaking =
false;
976 size_t currentCase = 1;
977 bool hasMatched =
false;
981 Boxed_Value match_value(this->children[0]->eval(t_ss));
983 while (!breaking && (currentCase < this->children.size())) {
985 if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
988 std::array<Boxed_Value, 2> p{match_value, this->children[currentCase]->children[0]->eval(t_ss)};
989 if (hasMatched || boxed_cast<bool>(t_ss->call_function(
"==", m_loc,
Function_Params{p}, t_ss.conversions()))) {
990 this->children[currentCase]->eval(t_ss);
996 }
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
997 this->children[currentCase]->eval(t_ss);
1008 mutable std::atomic_uint_fast32_t m_loc = {0};
1011 template<
typename T>
1014 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children)) {
1015 assert(this->children.size() == 2);
1021 this->children[1]->eval(t_ss);
1027 template<
typename T>
1030 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children)) {
1031 assert(this->children.size() == 1);
1037 this->children[0]->eval(t_ss);
1043 template<
typename T>
1046 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) {
1051 std::vector<Boxed_Value> vec;
1052 if (!this->children.empty()) {
1053 vec.reserve(this->children[0]->children.size());
1054 for (
const auto &child : this->children[0]->children) {
1055 vec.push_back(detail::clone_if_necessary(child->eval(t_ss), m_loc, t_ss));
1060 throw exception::eval_error(
"Can not find appropriate 'clone' or copy constructor for vector elements");
1065 mutable std::atomic_uint_fast32_t m_loc = {0};
1068 template<
typename T>
1071 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) {
1076 std::map<std::string, Boxed_Value> retval;
1078 for (
const auto &child : this->children[0]->children) {
1079 retval.insert(std::make_pair(t_ss->
boxed_cast<std::string>(child->children[0]->eval(t_ss)),
1080 detail::clone_if_necessary(child->children[1]->eval(t_ss), m_loc, t_ss)));
1085 throw exception::eval_error(
"Can not find appropriate copy constructor or 'clone' while inserting into Map.",
1094 mutable std::atomic_uint_fast32_t m_loc = {0};
1097 template<
typename T>
1100 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) {
1104 if (!this->children.empty()) {
1112 template<
typename T>
1115 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) {
1120 const auto num_children = this->children.size();
1122 if (num_children > 0) {
1123 for (
size_t i = 0; i < num_children - 1; ++i) {
1124 this->children[i]->eval(t_ss);
1126 return this->children.back()->eval(t_ss);
1138 template<
typename T>
1141 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children)) {
1142 assert(this->children.size() == 1);
1147 t_ss.add_object(this->children[0]->text, bv);
1152 template<
typename T>
1155 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children))
1156 , m_oper(Operators::to_operator(this->text,
true)) {
1164 if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic()) {
1165 if ((m_oper == Operators::Opers::pre_increment || m_oper == Operators::Opers::pre_decrement) && bv.is_const()) {
1166 throw exception::eval_error(
"Error with prefix operator evaluation: cannot modify constant value.");
1168 return Boxed_Number::do_oper(m_oper, bv);
1172 return t_ss->call_function(this->text, m_loc,
Function_Params{bv}, t_ss.conversions());
1175 throw exception::eval_error(
"Error with prefix operator evaluation: '" + this->text +
"'", e.parameters, e.functions,
false, *t_ss);
1180 Operators::Opers m_oper = Operators::Opers::invalid;
1181 mutable std::atomic_uint_fast32_t m_loc = {0};
1184 template<
typename T>
1187 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) {
1193 template<
typename T>
1196 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) {
1202 template<
typename T>
1216 template<
typename T>
1219 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) {
1223 template<
typename T>
1226 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) {
1230 template<
typename T>
1233 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) {
1238 std::array<Boxed_Value, 2> params{this->children[0]->children[0]->children[0]->eval(t_ss),
1239 this->children[0]->children[0]->children[1]->eval(t_ss)};
1241 return t_ss->call_function(
"generate_range", m_loc,
Function_Params{params}, t_ss.conversions());
1243 throw exception::eval_error(
"Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions,
false, *t_ss);
1248 mutable std::atomic_uint_fast32_t m_loc = {0};
1251 template<
typename T>
1254 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) {
1260 size_t end_point = this->children.size();
1261 if (this->children.back()->identifier == AST_Node_Type::Finally) {
1262 assert(end_point > 0);
1263 end_point = this->children.size() - 1;
1265 for (
size_t i = 1; i < end_point; ++i) {
1267 auto &catch_block = *this->children[i];
1269 if (catch_block.children.size() == 1) {
1271 retval = catch_block.children[0]->eval(t_ss);
1273 }
else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) {
1280 t_ss.add_object(name, t_except);
1282 if (catch_block.children.size() == 2) {
1284 retval = catch_block.children[1]->eval(t_ss);
1289 if (this->children.back()->identifier == AST_Node_Type::Finally) {
1290 this->children.back()->children[0]->eval(t_ss);
1305 retval = this->children[0]->eval(t_ss);
1307 retval = handle_exception(t_ss,
Boxed_Value(std::ref(e)));
1308 }
catch (
const std::runtime_error &e) {
1309 retval = handle_exception(t_ss,
Boxed_Value(std::ref(e)));
1310 }
catch (
const std::out_of_range &e) {
1311 retval = handle_exception(t_ss,
Boxed_Value(std::ref(e)));
1312 }
catch (
const std::exception &e) {
1313 retval = handle_exception(t_ss,
Boxed_Value(std::ref(e)));
1315 retval = handle_exception(t_ss, e);
1317 if (this->children.back()->identifier == AST_Node_Type::Finally) {
1318 this->children.back()->children[0]->eval(t_ss);
1323 if (this->children.back()->identifier == AST_Node_Type::Finally) {
1324 retval = this->children.back()->children[0]->eval(t_ss);
1331 template<
typename T>
1334 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) {
1338 template<
typename T>
1341 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) {
1345 template<
typename T>
1347 std::shared_ptr<AST_Node_Impl<T>> m_body_node;
1348 std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
1352 AST_Node_Type::Method,
1354 std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
1355 std::make_move_iterator(
1362 AST_Node_Impl_Ptr<T> guardnode;
1364 const std::string &class_name = this->children[0]->text;
1367 std::vector<std::string> t_param_names{
"this"};
1370 if ((this->children.size() > 2) && (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
1372 t_param_names.insert(t_param_names.end(), args.begin(), args.end());
1376 const size_t numparams = t_param_names.size();
1378 std::shared_ptr<dispatch::Proxy_Function_Base> guard;
1379 std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
1381 guard = dispatch::make_dynamic_proxy_function(
1382 [engine, t_param_names, guardnode = m_guard_node](
const Function_Params &t_params) {
1383 return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params);
1385 static_cast<int>(numparams),
1390 const std::string &function_name = this->children[1]->text;
1392 if (function_name == class_name) {
1393 param_types.push_front(class_name,
Type_Info());
1395 t_ss->
add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(
1397 dispatch::make_dynamic_proxy_function(
1398 [engine, t_param_names, node = m_body_node](
const Function_Params &t_params) {
1399 return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
1401 static_cast<int>(numparams),
1410 auto type = t_ss->
get_type(class_name,
false);
1411 param_types.push_front(class_name, type);
1413 t_ss->
add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(
1415 dispatch::make_dynamic_proxy_function(
1416 [engine, t_param_names, node = m_body_node](
const Function_Params &t_params) {
1417 return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
1419 static_cast<int>(numparams),
1433 template<
typename T>
1436 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) {
1440 std::string class_name = this->children[0]->text;
1443 std::string attr_name = this->children[1]->text;
1445 t_ss->
add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(std::move(class_name),
1447 return t_obj.get_attr(attr_name);
1452 this->children[1]->text);
1460 template<
typename T>
1463 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children)) {
1464 assert(this->children.size() == 2);
1468 return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
1469 && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
1473 template<
typename T>
1476 :
AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) {
1477 assert(this->children.size() == 2);
1481 return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
1482 || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
void add(const Type_Conversion &d)
Add a new conversion for upcasting to a base class.
Definition: dispatchkit.hpp:381
Exception thrown in the case that an object name is invalid because it already exists in current cont...
Definition: dispatchkit.hpp:97
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
Definition: chaiscript_eval.hpp:417
Definition: chaiscript_eval.hpp:276
Definition: chaiscript_eval.hpp:1339
Compile time deduced information about a type.
Definition: type_info.hpp:27
Creates a new scope then pops it on destruction.
Definition: chaiscript_common.hpp:681
Special type indicating a call to 'continue'.
Definition: chaiscript_common.hpp:639
Boxed_Value const_var(const T &t)
Takes an object and returns an immutable Boxed_Value.
Definition: boxed_value.hpp:336
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
Definition: chaiscript_eval.hpp:863
Definition: chaiscript_eval.hpp:365
Creates a new function call and pops it on destruction.
Definition: chaiscript_common.hpp:661
Definition: chaiscript_eval.hpp:822
Definition: chaiscript_eval.hpp:969
Definition: chaiscript_eval.hpp:710
Definition: chaiscript_eval.hpp:1346
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions=nullptr)
Function for extracting a value stored in a Boxed_Value object.
Definition: boxed_cast.hpp:71
Exception thrown if a function's guard fails.
Definition: proxy_functions.hpp:285
Namespace chaiscript contains every API call that the average user will be concerned with...
Definition: function_params.hpp:16
Definition: chaiscript_eval.hpp:44
Definition: chaiscript_eval.hpp:1139
Definition: chaiscript_eval.hpp:498
Definition: chaiscript_eval.hpp:173
Definition: chaiscript_eval.hpp:511
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
Definition: chaiscript_eval.hpp:827
Definition: chaiscript_eval.hpp:940
Definition: chaiscript_eval.hpp:1203
std::pair< size_t, std::shared_ptr< std::vector< Proxy_Function > > > get_function(std::string_view t_name, const size_t t_hint) const
Return a function by name.
Definition: dispatchkit.hpp:612
Definition: chaiscript_eval.hpp:157
Pure virtual base class for all Proxy_Function implementations Proxy_Functions are a type erasure of ...
Definition: proxy_functions.hpp:175
AST_Node_Type
Types of AST nodes available to the parser and eval.
Definition: chaiscript_common.hpp:66
Definition: chaiscript_eval.hpp:553
A wrapper for holding any valid C++ type.
Definition: boxed_value.hpp:24
Definition: chaiscript_eval.hpp:259
Definition: chaiscript_eval.hpp:410
Thrown in the event that a Boxed_Value cannot be cast to the desired type.
Definition: bad_boxed_cast.hpp:31
Definition: chaiscript_eval.hpp:1461
Definition: chaiscript_eval.hpp:576
Definition: proxy_functions.hpp:48
Definition: chaiscript_eval.hpp:214
Definition: chaiscript_eval.hpp:1028
Definition: chaiscript_eval.hpp:1113
Definition: chaiscript_eval.hpp:358
Definition: chaiscript_eval.hpp:693
Boxed_Value dispatch(const Funcs &funcs, const Function_Params &plist, const Type_Conversions_State &t_conversions)
Take a vector of functions and a vector of parameters.
Definition: proxy_functions.hpp:779
Creates a new scope then pops it on destruction.
Definition: chaiscript_common.hpp:643
Definition: chaiscript_eval.hpp:857
Special type indicating a call to 'break'.
Definition: chaiscript_common.hpp:635
Definition: chaiscript_eval.hpp:294
Definition: chaiscript_eval.hpp:1098
Definition: chaiscript_eval.hpp:1194
Struct that doubles as both a parser ast_node and an AST node.
Definition: chaiscript_common.hpp:174
Definition: chaiscript_eval.hpp:1217
Boxed_Value add_global_no_throw(Boxed_Value obj, std::string name)
Adds a new global (non-const) shared object, between all the threads.
Definition: dispatchkit.hpp:448
std::shared_ptr< const dispatch::Proxy_Function_Base > Const_Proxy_Function
Const version of Proxy_Function.
Definition: proxy_functions.hpp:281
Definition: chaiscript_common.hpp:151
Classes which may be thrown during error cases when ChaiScript is executing.
Definition: bad_boxed_cast.hpp:25
Exception thrown when there is a mismatch in number of parameters during Proxy_Function execution...
Definition: proxy_functions_detail.hpp:38
const StackData & get_stack_data() const noexcept
Returns the current stack make const/non const versions.
Definition: dispatchkit.hpp:1022
Definition: chaiscript_eval.hpp:841
Definition: chaiscript_eval.hpp:1474
Definition: chaiscript_eval.hpp:1185
Definition: chaiscript_eval.hpp:1012
Type_Info get_type(std::string_view name, bool t_throw=true) const
Returns the type info for a named type.
Definition: dispatchkit.hpp:563
Special type for returned values.
Definition: chaiscript_common.hpp:630
Definition: dynamic_object.hpp:38
Definition: chaiscript_eval.hpp:1044
decltype(auto) boxed_cast(const Boxed_Value &bv) const
casts an object while applying any Dynamic_Conversion available
Definition: dispatchkit.hpp:375
Definition: chaiscript_eval.hpp:795
Definition: chaiscript_eval.hpp:1434
Definition: chaiscript_eval.hpp:1224
Definition: chaiscript_eval.hpp:1231
Definition: chaiscript_eval.hpp:347
Definition: dispatchkit.hpp:1166
Exception thrown in the case that a method dispatch fails because no matching function was found...
Definition: proxy_functions.hpp:667
Definition: chaiscript_eval.hpp:631
Definition: chaiscript_eval.hpp:1332
Errors generated during parsing or evaluation.
Definition: chaiscript_common.hpp:301
Definition: chaiscript_eval.hpp:1153
Proxy_Function fun(T &&t)
Creates a new Proxy_Function object from a free function, member function or data member...
Definition: register_function.hpp:81
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept
Definition: boxed_value.hpp:237
Definition: chaiscript_eval.hpp:1069
Main class for the dispatchkit.
Definition: dispatchkit.hpp:354
Definition: boxed_number.hpp:29
Definition: chaiscript_eval.hpp:1252
Definition: chaiscript_eval.hpp:530
Definition: chaiscript_eval.hpp:678