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