ChaiScript / ChaiScript
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-2018, 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::exception {
38
class bad_boxed_cast;
39
}  // namespace chaiscript::exception
40

41
namespace chaiscript
42
{
43
  /// \brief Classes and functions that are part of the runtime eval system
44
  namespace eval
45
  {
46
    template<typename T> struct AST_Node_Impl;
47

48
    template<typename T> using AST_Node_Impl_Ptr = typename std::unique_ptr<AST_Node_Impl<T>>;
49

50
    namespace detail
51
    {
52
      /// Helper function that will set up the scope around a function call, including handling the named function parameters
53
      template<typename T>
54 1
      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 Function_Params &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
55 1
        chaiscript::detail::Dispatch_State state(t_ss);
56

57
        const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
58
          if (auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
59
              !stack.empty() && stack.back().first == "__this") 
60
          {
61
            return &stack.back().second;
62
          } else if (!t_vals.empty()) {
63
            return &t_vals[0];
64
          } else {
65
            return nullptr;
66
          }
67 1
        }();
68

69 1
        chaiscript::eval::detail::Stack_Push_Pop tpp(state);
70 1
        if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); }
71

72 1
        if (t_locals) {
73 1
          for (const auto &[name, value] : *t_locals) {
74 1
            state.add_object(name, value);
75
          }
76
        }
77

78 1
        for (size_t i = 0; i < t_param_names.size(); ++i) {
79 1
          if (t_param_names[i] != "this") {
80 1
            state.add_object(t_param_names[i], t_vals[i]);
81
          }
82
        }
83

84
        try {
85 1
          return t_node.eval(state);
86 1
        } catch (detail::Return_Value &rv) {
87 1
          return std::move(rv.retval);
88
        } 
89
      }
90

91 1
      inline Boxed_Value clone_if_necessary(Boxed_Value incoming, std::atomic_uint_fast32_t &t_loc, const chaiscript::detail::Dispatch_State &t_ss)
92
      {
93 1
        if (!incoming.is_return_value())
94
        {
95 1
          if (incoming.get_type_info().is_arithmetic()) {
96 1
            return Boxed_Number::clone(incoming);
97 1
          } else if (incoming.get_type_info().bare_equal_type_info(typeid(bool))) {
98 1
            return Boxed_Value(*static_cast<const bool*>(incoming.get_const_ptr()));
99 1
          } else if (incoming.get_type_info().bare_equal_type_info(typeid(std::string))) {
100 1
            return Boxed_Value(*static_cast<const std::string *>(incoming.get_const_ptr()));
101
          } else {
102 1
            std::array<Boxed_Value, 1> params{std::move(incoming)};
103 1
            return t_ss->call_function("clone", t_loc, Function_Params{params}, t_ss.conversions());
104
          }
105
        } else {
106 1
          incoming.reset_return_value();
107 1
          return incoming;
108
        }
109
      }
110
    }
111

112
    template<typename T>
113
    struct AST_Node_Impl : AST_Node 
114
    {
115 1
      AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, 
116
               std::vector<AST_Node_Impl_Ptr<T>> t_children = std::vector<AST_Node_Impl_Ptr<T>>())
117 1
        : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)),
118 1
          children(std::move(t_children))
119
      {
120
      }
121

122 1
      static bool get_scoped_bool_condition(const AST_Node_Impl<T> &node, const chaiscript::detail::Dispatch_State &t_ss) {
123 1
        chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
124 1
        return get_bool_condition(node.eval(t_ss), t_ss);
125
      }
126

127

128 1
      std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
129 1
        std::vector<std::reference_wrapper<AST_Node>> retval;
130 1
        retval.reserve(children.size());
131 1
        for (auto &child : children) {
132 1
          retval.emplace_back(*child);
133
        }
134

135 1
        return retval;
136
      }
137

138 1
      Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final
139
      {
140
        try {
141 1
          T::trace(t_e, this);
142 1
          return eval_internal(t_e);
143 1
        } catch (exception::eval_error &ee) {
144 1
          ee.call_stack.push_back(*this);
145 1
          throw;
146
        }
147
      }
148

149
      std::vector<AST_Node_Impl_Ptr<T>> children;
150

151
      protected:
152 0
        virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
153
        {
154 0
          throw std::runtime_error("Undispatched ast_node (internal error)");
155
        }
156
    };
157

158

159
    template<typename T>
160
    struct Compiled_AST_Node : AST_Node_Impl<T> {
161 1
        Compiled_AST_Node(AST_Node_Impl_Ptr<T> t_original_node, std::vector<AST_Node_Impl_Ptr<T>> t_children,
162
            std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) :
163 1
          AST_Node_Impl<T>(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)),
164 1
          m_func(std::move(t_func)),
165 1
          m_original_node(std::move(t_original_node))
166 1
        { }
167

168 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
169 1
          return m_func(this->children, t_ss);
170
        }
171

172
        std::function<Boxed_Value (const std::vector<AST_Node_Impl_Ptr<T>> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func;
173
        AST_Node_Impl_Ptr<T> m_original_node;
174
    };
175

176

177
    template<typename T>
178
    struct Fold_Right_Binary_Operator_AST_Node : AST_Node_Impl<T> {
179 1
        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) :
180 1
          AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),
181 1
          m_oper(Operators::to_operator(t_oper)),
182 1
          m_rhs(std::move(t_rhs))
183 1
        { }
184

185 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
186 1
          return do_oper(t_ss, this->text, this->children[0]->eval(t_ss));
187
        }
188

189
      protected:
190 1
        Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, 
191
            const std::string &t_oper_string, const Boxed_Value &t_lhs) const
192
        {
193
          try {
194 1
            if (t_lhs.get_type_info().is_arithmetic())
195
            {
196
              // If it's an arithmetic operation we want to short circuit dispatch
197
              try{
198 1
                return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs);
199 0
              } catch (const chaiscript::exception::arithmetic_error &) {
200 0
                throw;
201 1
              } catch (...) {
202 1
                throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
203
              }
204
            } else {
205 1
              chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
206 1
              std::array<Boxed_Value, 2> params{t_lhs, m_rhs};
207 1
              fpp.save_params(Function_Params{params});
208 1
              return t_ss->call_function(t_oper_string, m_loc, Function_Params{params}, t_ss.conversions());
209
            }
210
          }
211 1
          catch(const exception::dispatch_error &e){
212 1
            throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
213
          }
214
        }
215

216
      private:
217
        Operators::Opers m_oper;
218
        Boxed_Value m_rhs;
219
        mutable std::atomic_uint_fast32_t m_loc = {0};
220
    };
221

222

223
    template<typename T>
224
    struct Binary_Operator_AST_Node : AST_Node_Impl<T> {
225 1
        Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
226 1
          AST_Node_Impl<T>(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)),
227 1
          m_oper(Operators::to_operator(t_oper))
228 1
        { }
229

230 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
231 1
          auto lhs = this->children[0]->eval(t_ss);
232 1
          auto rhs = this->children[1]->eval(t_ss);
233 1
          return do_oper(t_ss, m_oper, this->text, lhs, rhs);
234
        }
235

236
      protected:
237 1
        Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, 
238
            Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const
239
        {
240
          try {
241 1
            if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic())
242
            {
243
              // If it's an arithmetic operation we want to short circuit dispatch
244
              try{
245 1
                return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
246 1
              } catch (const chaiscript::exception::arithmetic_error &) {
247 1
                throw;
248 1
              } catch (...) {
249 1
                throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
250
              }
251
            } else {
252 1
              chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
253 1
              std::array<Boxed_Value, 2> params{t_lhs, t_rhs};
254 1
              fpp.save_params(Function_Params(params));
255 1
              return t_ss->call_function(t_oper_string, m_loc, Function_Params(params), t_ss.conversions());
256
            }
257
          }
258 1
          catch(const exception::dispatch_error &e){
259 1
            throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
260
          }
261
        }
262

263
      private:
264
        Operators::Opers m_oper;
265
        mutable std::atomic_uint_fast32_t m_loc = {0};
266
    };
267

268

269
    template<typename T>
270
    struct Constant_AST_Node final : AST_Node_Impl<T> {
271 1
      Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value)
272 1
        : AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)),
273 1
          m_value(std::move(t_value))
274
      {
275
      }
276

277 1
      explicit Constant_AST_Node(Boxed_Value t_value)
278
        : AST_Node_Impl<T>("", AST_Node_Type::Constant, Parse_Location()),
279 1
          m_value(std::move(t_value))
280
      {
281
      }
282

283 1
      Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override {
284 1
        return m_value;
285
      }
286

287
      Boxed_Value m_value;
288
    };
289

290
    template<typename T>
291
    struct Id_AST_Node final : AST_Node_Impl<T> {
292 1
        Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
293 1
          AST_Node_Impl<T>(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc))
294 1
        { }
295

296 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
297
          try {
298 1
            return t_ss.get_object(this->text, m_loc);
299
          }
300 1
          catch (std::exception &) {
301 1
            throw exception::eval_error("Can not find object: " + this->text);
302
          }
303
        }
304

305
      private:
306
        mutable std::atomic_uint_fast32_t m_loc = {0};
307
    };
308

309
    template<typename T>
310
    struct Fun_Call_AST_Node : AST_Node_Impl<T> {
311 1
        Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
312 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { 
313
            assert(!this->children.empty());
314
          }
315

316
        template<bool Save_Params>
317 1
        Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const
318
        {
319 1
          chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
320

321 1
          std::vector<Boxed_Value> params;
322

323 1
          params.reserve(this->children[1]->children.size());
324 1
          for (const auto &child : this->children[1]->children) {
325 1
            params.push_back(child->eval(t_ss));
326
          }
327

328
          if (Save_Params) {
329 1
            fpp.save_params(Function_Params{params});
330
          }
331

332 1
          Boxed_Value fn(this->children[0]->eval(t_ss));
333

334
          try {
335 1
            return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(Function_Params{params}, t_ss.conversions());
336
          }
337 1
          catch(const exception::dispatch_error &e){
338 1
            throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
339
          }
340 1
          catch(const exception::bad_boxed_cast &){
341
            try {
342
              using ConstFunctionTypeRef = const Const_Proxy_Function &;
343 1
              Const_Proxy_Function f = t_ss->boxed_cast<ConstFunctionTypeRef>(fn);
344
              // handle the case where there is only 1 function to try to call and dispatch fails on it
345 1
              throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(f), false, *t_ss);
346 1
            } catch (const exception::bad_boxed_cast &) {
347 1
              throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
348
            }
349
          }
350 1
          catch(const exception::arity_error &e){
351 1
            throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
352
          }
353 1
          catch(const exception::guard_error &e){
354 1
            throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
355
          }
356 1
          catch(detail::Return_Value &rv) {
357 1
            return rv.retval;
358
          }
359
        }
360

361 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
362
        {
363 1
          return do_eval_internal<true>(t_ss);
364
        }
365

366
    };
367

368

369
    template<typename T>
370
    struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node<T> {
371 1
        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) :
372 1
          Fun_Call_AST_Node<T>(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { }
373

374 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
375
        {
376 1
          return this->template do_eval_internal<false>(t_ss);
377
        }
378
    };
379

380

381

382

383

384
    template<typename T>
385
    struct Arg_AST_Node final : AST_Node_Impl<T> {
386 1
        Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
387 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
388

389
    };
390

391
    template<typename T>
392
    struct Arg_List_AST_Node final : AST_Node_Impl<T> {
393 1
        Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
394 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { }
395

396

397 1
        static std::string get_arg_name(const AST_Node_Impl<T> &t_node) {
398 1
          if (t_node.children.empty())
399
          {
400 0
            return t_node.text;
401 1
          } else if (t_node.children.size() == 1) {
402 1
            return t_node.children[0]->text;
403
          } else {
404 1
            return t_node.children[1]->text;
405
          }
406
        }
407

408 1
        static std::vector<std::string> get_arg_names(const AST_Node_Impl<T> &t_node) {
409 1
          std::vector<std::string> retval;
410

411 1
          for (const auto &node : t_node.children)
412
          {
413 1
            retval.push_back(get_arg_name(*node));
414
          }
415

416 1
          return retval;
417
        }
418

419 1
        static std::pair<std::string, Type_Info> get_arg_type(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) 
420
        {
421 1
          if (t_node.children.size() < 2)
422
          {
423 1
            return {};
424
          } else {
425 1
            return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)};
426
          }
427
        }
428

429 1
        static dispatch::Param_Types get_arg_types(const AST_Node_Impl<T> &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
430 1
          std::vector<std::pair<std::string, Type_Info>> retval;
431

432 1
          for (const auto &child : t_node.children)
433
          {
434 1
            retval.push_back(get_arg_type(*child, t_ss));
435
          }
436

437 1
          return dispatch::Param_Types(std::move(retval));
438
        }
439
    };
440

441
    template<typename T>
442
    struct Equation_AST_Node final : AST_Node_Impl<T> {
443 1
        Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
444 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)), 
445 1
          m_oper(Operators::to_operator(this->text))
446
        { assert(this->children.size() == 2); }
447

448

449 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
450 1
          chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
451

452 1
          auto params = [&](){
453
            // The RHS *must* be evaluated before the LHS
454
            // consider `var range = range(x)`
455
            // if we declare the variable in scope first, then the name lookup fails
456
            // for the RHS
457
            auto rhs = this->children[1]->eval(t_ss);
458
            auto lhs = this->children[0]->eval(t_ss);
459
            std::array<Boxed_Value, 2> p{std::move(lhs), std::move(rhs)};
460
            return p;
461
          }();
462

463 1
          if (params[0].is_return_value()) {
464 1
            throw exception::eval_error("Error, cannot assign to temporary value.");
465 1
          } else if (params[0].is_const()) {
466 1
            throw exception::eval_error("Error, cannot assign to constant value.");
467
          }
468

469

470 1
          if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() &&
471 1
              params[1].get_type_info().is_arithmetic())
472
          {
473
            try {
474 1
              return Boxed_Number::do_oper(m_oper, params[0], params[1]);
475 0
            } catch (const std::exception &) {
476 0
              throw exception::eval_error("Error with unsupported arithmetic assignment operation.");
477
            }
478 1
          } else if (m_oper == Operators::Opers::assign) {
479
            try {
480

481 1
              if (params[0].is_undef()) {
482 1
                if (!this->children.empty()
483 1
                     && ((this->children[0]->identifier == AST_Node_Type::Reference)
484 1
                         || (!this->children[0]->children.empty()
485 1
                              && this->children[0]->children[0]->identifier == AST_Node_Type::Reference)
486
                       )
487
                   )
488

489
                {
490
                  /// \todo This does not handle the case of an unassigned reference variable
491
                  ///       being assigned outside of its declaration
492 1
                  params[0].assign(params[1]);
493 1
                  params[0].reset_return_value();
494 1
                  return params[1];
495
                } else {
496 1
                  params[1] = detail::clone_if_necessary(std::move(params[1]), m_clone_loc, t_ss);
497
                }
498
              }
499

500
              try {
501 1
                return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions());
502
              }
503 1
              catch(const exception::dispatch_error &e){
504 1
                throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
505
              }
506
            }
507 0
            catch(const exception::dispatch_error &e){
508 0
              throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss);
509
            }
510
          }
511 1
          else if (this->text == ":=") {
512 0
            if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) {
513 1
              params[0].assign(params[1]);
514 1
              params[0].reset_return_value();
515
            } else {
516 0
              throw exception::eval_error("Mismatched types in equation");
517
            }
518
          }
519
          else {
520
            try {
521 1
              return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions());
522 1
            } catch(const exception::dispatch_error &e){
523 1
              throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
524
            }
525
          }
526

527 1
          return params[1];
528
        }
529

530
      private:
531
        Operators::Opers m_oper;
532
        mutable std::atomic_uint_fast32_t m_loc = {0};
533
        mutable std::atomic_uint_fast32_t m_clone_loc = {0};
534
    };
535

536
    template<typename T>
537
    struct Global_Decl_AST_Node final : AST_Node_Impl<T> {
538 1
        Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
539 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { }
540

541 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
542
          const std::string &idname =
543
            [&]()->const std::string & {
544
              if (this->children[0]->identifier == AST_Node_Type::Reference) {
545
                return this->children[0]->children[0]->text;
546
              } else {
547
                return this->children[0]->text;
548
              }
549 1
            }();
550

551 1
          return t_ss->add_global_no_throw(Boxed_Value(), idname);
552

553
        }
554
    };
555

556

557
    template<typename T>
558
    struct Var_Decl_AST_Node final : AST_Node_Impl<T> {
559 1
        Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
560 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { }
561

562 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
563 1
          const std::string &idname = this->children[0]->text;
564

565
          try {
566 1
            Boxed_Value bv;
567 1
            t_ss.add_object(idname, bv);
568 1
            return bv;
569 1
          } catch (const exception::name_conflict_error &e) {
570 1
            throw exception::eval_error("Variable redefined '" + e.name() + "'");
571
          }
572
        }
573
    };
574

575
    template<typename T>
576
    struct Assign_Decl_AST_Node final : AST_Node_Impl<T> {
577 1
        Assign_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
578 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Assign_Decl, std::move(t_loc), std::move(t_children)) { }
579

580 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
581 1
          const std::string &idname = this->children[0]->text;
582

583
          try {
584 1
            Boxed_Value bv(detail::clone_if_necessary(this->children[1]->eval(t_ss), m_loc, t_ss));
585 1
            bv.reset_return_value();
586 1
            t_ss.add_object(idname, bv);
587 1
            return bv;
588 1
          } catch (const exception::name_conflict_error &e) {
589 1
            throw exception::eval_error("Variable redefined '" + e.name() + "'");
590
          }
591
        }
592
      private:
593
        mutable std::atomic_uint_fast32_t m_loc = {0};
594
    };
595

596

597
    template<typename T>
598
    struct Array_Call_AST_Node final : AST_Node_Impl<T> {
599 1
        Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
600 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { }
601

602 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
603 1
          chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
604

605 1
          std::array<Boxed_Value, 2> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
606

607
          try {
608 1
            fpp.save_params(Function_Params{params});
609 1
            return t_ss->call_function("[]", m_loc, Function_Params{params}, t_ss.conversions());
610
          }
611 1
          catch(const exception::dispatch_error &e){
612 1
            throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
613
          }
614
        }
615

616

617
      private:
618
        mutable std::atomic_uint_fast32_t m_loc = {0};
619
    };
620

621
    template<typename T>
622
    struct Dot_Access_AST_Node final : AST_Node_Impl<T> {
623 1
        Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
624 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)),
625
          m_fun_name(
626 1
              ((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))?
627
              this->children[1]->children[0]->text:this->children[1]->text) { }
628

629 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
630 1
          chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
631

632

633 1
          Boxed_Value retval = this->children[0]->eval(t_ss);
634 1
          auto params = make_vector(retval);
635

636 1
          bool has_function_params = false;
637 1
          if (this->children[1]->children.size() > 1) {
638 1
            has_function_params = true;
639 1
            for (const auto &child : this->children[1]->children[1]->children) {
640 1
              params.push_back(child->eval(t_ss));
641
            }
642
          }
643

644 1
          fpp.save_params(Function_Params{params});
645

646
          try {
647 1
            retval = t_ss->call_member(m_fun_name, m_loc, Function_Params{params}, has_function_params, t_ss.conversions());
648
          }
649 1
          catch(const exception::dispatch_error &e){
650 1
            if (e.functions.empty())
651
            {
652 1
              throw exception::eval_error("'" + m_fun_name + "' is not a function.");
653
            } else {
654 1
              throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss);
655
            }
656
          }
657 0
          catch(detail::Return_Value &rv) {
658 0
            retval = std::move(rv.retval);
659
          }
660

661 1
          if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
662
            try {
663 0
              std::array<Boxed_Value, 2> p{retval, this->children[1]->children[1]->eval(t_ss)};
664 0
              retval = t_ss->call_function("[]", m_array_loc, Function_Params{p}, t_ss.conversions());
665
            }
666 0
            catch(const exception::dispatch_error &e){
667 0
              throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
668
            }
669
          }
670

671 1
          return retval;
672
        }
673

674
      private:
675
        mutable std::atomic_uint_fast32_t m_loc = {0};
676
        mutable std::atomic_uint_fast32_t m_array_loc = {0};
677
        const std::string m_fun_name;
678
    };
679

680

681
    template<typename T>
682
    struct Lambda_AST_Node final : AST_Node_Impl<T> {
683 1
        Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
684
          AST_Node_Impl<T>(t_ast_node_text, 
685
              AST_Node_Type::Lambda, 
686 1
              std::move(t_loc), 
687
              std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()), 
688
                                                std::make_move_iterator(std::prev(t_children.end())))
689
              ),
690 1
          m_param_names(Arg_List_AST_Node<T>::get_arg_names(*this->children[1])),
691 1
          m_this_capture(has_this_capture(this->children[0]->children)),
692 1
          m_lambda_node(std::move(t_children.back()))
693 1
        { }
694

695 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
696

697 1
          const auto captures = [&]()->std::map<std::string, Boxed_Value>{
698
            std::map<std::string, Boxed_Value> named_captures;
699
            for (const auto &capture : this->children[0]->children) {
700
              named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
701
            }
702
            return named_captures;
703
          }();
704

705 1
          const auto numparams = this->children[1]->children.size();
706 1
          const auto param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
707

708 1
          std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
709

710
          return Boxed_Value(
711
              dispatch::make_dynamic_proxy_function(
712 1
                  [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures, 
713 1
                   this_capture = this->m_this_capture] (const Function_Params &t_params)
714
                  {
715
                    return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture);
716
                  },
717 1
                  static_cast<int>(numparams), m_lambda_node, param_types
718
                )
719 1
              );
720
        }
721

722 1
        static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) noexcept {
723 1
          return std::any_of(std::begin(children), std::end(children),
724 1
                [](const auto &child){
725 1
                  return child->children[0]->text == "this";
726
                }
727 1
              );
728
        }
729

730
      private:
731
        const std::vector<std::string> m_param_names;
732
        const bool m_this_capture = false;
733
        const std::shared_ptr<AST_Node_Impl<T>> m_lambda_node;
734
    };
735

736
    template<typename T>
737
    struct Scopeless_Block_AST_Node final : AST_Node_Impl<T> {
738 1
        Scopeless_Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
739 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) { }
740

741 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
742 1
          const auto num_children = this->children.size();
743 1
          for (size_t i = 0; i < num_children-1; ++i) {
744 1
            this->children[i]->eval(t_ss);
745
          }
746 1
          return this->children.back()->eval(t_ss);
747
        }
748
    };
749

750
    template<typename T>
751
    struct Block_AST_Node final : AST_Node_Impl<T> {
752 1
        Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
753 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { }
754

755 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
756 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
757

758 1
          const auto num_children = this->children.size();
759 1
          for (size_t i = 0; i < num_children-1; ++i) {
760 1
            this->children[i]->eval(t_ss);
761
          }
762 1
          return this->children.back()->eval(t_ss);
763
        }
764
    };
765

766
    template<typename T>
767
    struct Def_AST_Node final : AST_Node_Impl<T> {
768

769
        std::shared_ptr<AST_Node_Impl<T>> m_body_node;
770
        std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
771

772 1
        Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
773 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), 
774
              std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()), 
775 1
                                                std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1)))
776
              ),
777
              // This apparent use after move is safe because we are only moving out the specific elements we need
778
              // on each operation.
779 1
              m_body_node(get_body_node(std::move(t_children))),
780 1
              m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
781

782 1
        { }
783

784 1
        static std::shared_ptr<AST_Node_Impl<T>> get_guard_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec, bool has_guard)
785
        {
786 1
          if (has_guard) {
787 1
            return std::move(*std::prev(vec.end(), 2));
788
          } else {
789 1
            return {};
790
          }
791
        }
792

793 1
        static std::shared_ptr<AST_Node_Impl<T>> get_body_node(std::vector<AST_Node_Impl_Ptr<T>> &&vec)
794
        {
795 1
          return std::move(vec.back());
796
        }
797

798 1
        static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset) noexcept
799
        {
800 1
          if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) {
801 1
            if (t_children.size() > 3 + offset) {
802 1
              return true;
803
            }
804
          }
805
          else {
806 1
            if (t_children.size() > 2 + offset) {
807 1
              return true;
808
            }
809
          }
810 1
          return false;
811
        }
812

813 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
814 1
          std::vector<std::string> t_param_names;
815 1
          size_t numparams = 0;
816

817 1
          dispatch::Param_Types param_types;
818

819 1
          if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
820 1
            numparams = this->children[1]->children.size();
821 1
            t_param_names = Arg_List_AST_Node<T>::get_arg_names(*this->children[1]);
822 1
            param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[1], t_ss);
823
          }
824

825 1
          std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
826 1
          std::shared_ptr<dispatch::Proxy_Function_Base> guard;
827 1
          if (m_guard_node) {
828 1
            guard = dispatch::make_dynamic_proxy_function(
829 1
                [engine, guardnode = m_guard_node, t_param_names](const Function_Params &t_params)
830
                {
831
                  return detail::eval_function(engine, *guardnode, t_param_names, t_params);
832
                },
833 1
                static_cast<int>(numparams), m_guard_node);
834
          }
835

836
          try {
837 1
            const std::string & l_function_name = this->children[0]->text;
838 1
            t_ss->add(
839
                dispatch::make_dynamic_proxy_function(
840 1
                  [engine, func_node = m_body_node, t_param_names](const Function_Params &t_params)
841
                  {
842
                    return detail::eval_function(engine, *func_node, t_param_names, t_params);
843
                  },
844 1
                  static_cast<int>(numparams), m_body_node,
845
                  param_types, guard), l_function_name);
846 1
          } catch (const exception::name_conflict_error &e) {
847 1
            throw exception::eval_error("Function redefined '" + e.name() + "'");
848
          }
849 1
          return void_var();
850
        }
851

852
    };
853

854
    template<typename T>
855
    struct While_AST_Node final : AST_Node_Impl<T> {
856 1
        While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
857 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { }
858

859 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
860 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
861

862
          try {
863 1
            while (this->get_scoped_bool_condition(*this->children[0], t_ss)) {
864
              try {
865 1
                this->children[1]->eval(t_ss);
866 1
              } catch (detail::Continue_Loop &) {
867
                // we got a continue exception, which means all of the remaining 
868
                // loop implementation is skipped and we just need to continue to
869
                // the next condition test
870
              }
871
            } 
872 1
          } catch (detail::Break_Loop &) {
873
            // loop was broken intentionally
874
          }
875

876 1
          return void_var();
877
        }
878
    };
879

880
    template<typename T>
881
    struct Class_AST_Node final : AST_Node_Impl<T> {
882 1
        Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
883 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { }
884

885 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
886 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
887

888
          /// \todo do this better
889
          // put class name in current scope so it can be looked up by the attrs and methods
890 1
          t_ss.add_object("_current_class_name", const_var(this->children[0]->text));
891

892 1
          this->children[1]->eval(t_ss);
893

894 1
          return void_var();
895
        }
896
    };
897

898

899
    template<typename T>
900
    struct If_AST_Node final : AST_Node_Impl<T> {
901 1
        If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
902 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) 
903
        { 
904
          assert(this->children.size() == 3);
905
        }
906

907 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
908 1
          if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) {
909 1
            return this->children[1]->eval(t_ss);
910
          } else {
911 1
            return this->children[2]->eval(t_ss);
912
          }
913
        }
914
    };
915

916
    template<typename T>
917
    struct Ranged_For_AST_Node final : AST_Node_Impl<T> {
918 1
        Ranged_For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
919 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children))
920 0
          { assert(this->children.size() == 3); }
921

922 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
923 1
          const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){
924
            uint_fast32_t hint = t_hint;
925
            auto [funs_loc, funs] = t_ss->get_function(t_name, hint);
926
            if (funs_loc != hint) { t_hint = uint_fast32_t(funs_loc); }
927
            return std::move(funs);
928
          };
929

930 1
          const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {
931
            return dispatch::dispatch(*t_funcs, Function_Params{t_param}, t_ss.conversions());
932
          };
933

934

935 1
          const std::string &loop_var_name = this->children[0]->text;
936 1
          Boxed_Value range_expression_result = this->children[1]->eval(t_ss);
937

938

939 1
          const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing){
940
            try {
941
              for (auto &&loop_var : ranged_thing) {
942
                // This scope push and pop might not be the best thing for perf
943
                // but we know it's 100% correct
944
                chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
945
                /// to-do make this if-constexpr with C++17 branch
946
                if (!std::is_same<std::decay_t<decltype(loop_var)>, Boxed_Value>::value) {
947
                  t_ss.add_get_object(loop_var_name, Boxed_Value(std::ref(loop_var)));
948
                } else {
949
                  t_ss.add_get_object(loop_var_name, Boxed_Value(loop_var));
950
                }
951
                try {
952
                  this->children[2]->eval(t_ss);
953 0
                } catch (detail::Continue_Loop &) {
954
                }
955
              }
956 0
            } catch (detail::Break_Loop &) {
957
              // loop broken
958
            }
959
            return void_var();
960
          };
961

962 1
          if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::vector<Boxed_Value>))) {
963 1
            return do_loop(boxed_cast<const std::vector<Boxed_Value> &>(range_expression_result));
964 1
          } else if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::map<std::string, Boxed_Value>))) {
965 1
            return do_loop(boxed_cast<const std::map<std::string, Boxed_Value> &>(range_expression_result));
966
          } else {
967 1
            const auto range_funcs = get_function("range", m_range_loc);
968 1
            const auto empty_funcs = get_function("empty", m_empty_loc);
969 1
            const auto front_funcs = get_function("front", m_front_loc);
970 1
            const auto pop_front_funcs = get_function("pop_front", m_pop_front_loc);
971

972
            try {
973 1
              const auto range_obj = call_function(range_funcs, range_expression_result);
974 1
              while (!boxed_cast<bool>(call_function(empty_funcs, range_obj))) {
975 1
                chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
976 1
                t_ss.add_get_object(loop_var_name, call_function(front_funcs, range_obj));
977
                try {
978 1
                  this->children[2]->eval(t_ss);
979 0
                } catch (detail::Continue_Loop &) {
980
                  // continue statement hit
981
                }
982 1
                call_function(pop_front_funcs, range_obj);
983
              }
984 0
            } catch (detail::Break_Loop &) {
985
              // loop broken
986
            }
987 1
            return void_var();
988
          }
989

990
        }
991

992
      private:
993
        mutable std::atomic_uint_fast32_t m_range_loc = {0};
994
        mutable std::atomic_uint_fast32_t m_empty_loc = {0};
995
        mutable std::atomic_uint_fast32_t m_front_loc = {0};
996
        mutable std::atomic_uint_fast32_t m_pop_front_loc = {0};
997
    };
998

999

1000
    template<typename T>
1001
    struct For_AST_Node final : AST_Node_Impl<T> {
1002 1
        For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1003 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children)) 
1004 0
          { assert(this->children.size() == 4); }
1005

1006 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
1007 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
1008

1009
          try {
1010 1
            for (
1011 1
                this->children[0]->eval(t_ss);
1012 1
                this->get_scoped_bool_condition(*this->children[1], t_ss);
1013 1
                this->children[2]->eval(t_ss)
1014
                ) {
1015
              try {
1016
                // Body of Loop
1017 1
                this->children[3]->eval(t_ss);
1018 0
              } catch (detail::Continue_Loop &) {
1019
                // we got a continue exception, which means all of the remaining 
1020
                // loop implementation is skipped and we just need to continue to
1021
                // the next iteration step
1022
              }
1023
            }
1024 1
          } catch (detail::Break_Loop &) {
1025
            // loop broken
1026
          }
1027

1028 1
          return void_var();
1029
        }
1030

1031
    };
1032

1033
    template<typename T>
1034
    struct Switch_AST_Node final : AST_Node_Impl<T> {
1035 1
        Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1036 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { }
1037

1038 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
1039 1
          bool breaking = false;
1040 1
          size_t currentCase = 1;
1041 1
          bool hasMatched = false;
1042

1043 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
1044

1045 1
          Boxed_Value match_value(this->children[0]->eval(t_ss));
1046

1047 1
          while (!breaking && (currentCase < this->children.size())) {
1048
            try {
1049 1
              if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
1050
                //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
1051
                try {
1052 1
                  std::array<Boxed_Value, 2> p{match_value, this->children[currentCase]->children[0]->eval(t_ss)};
1053 1
                  if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, Function_Params{p}, t_ss.conversions()))) {
1054 1
                    this->children[currentCase]->eval(t_ss);
1055 1
                    hasMatched = true;
1056
                  }
1057
                }
1058 0
                catch (const exception::bad_boxed_cast &) {
1059 0
                  throw exception::eval_error("Internal error: case guard evaluation not boolean");
1060
                }
1061
              }
1062 1
              else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
1063 1
                this->children[currentCase]->eval(t_ss);
1064 1
                hasMatched = true;
1065
              }
1066
            }
1067 1
            catch (detail::Break_Loop &) {
1068 1
              breaking = true;
1069
            }
1070 1
            ++currentCase;
1071
          }
1072 1
          return void_var();
1073
        }
1074

1075
        mutable std::atomic_uint_fast32_t m_loc = {0};
1076
    };
1077

1078
    template<typename T>
1079
    struct Case_AST_Node final : AST_Node_Impl<T> {
1080 1
        Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1081 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children)) 
1082 0
        { assert(this->children.size() == 2); /* how many children does it have? */ }
1083

1084 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
1085 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
1086

1087 1
          this->children[1]->eval(t_ss);
1088

1089 1
          return void_var();
1090
        }
1091
    };
1092
   
1093
    template<typename T>
1094
    struct Default_AST_Node final : AST_Node_Impl<T> {
1095 1
        Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1096 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children))
1097 0
        { assert(this->children.size() == 1); }
1098

1099 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
1100 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
1101

1102 1
          this->children[0]->eval(t_ss);
1103

1104 1
          return void_var();
1105
        }
1106
    };
1107

1108

1109
    template<typename T>
1110
    struct Inline_Array_AST_Node final : AST_Node_Impl<T> {
1111 1
        Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1112 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { }
1113

1114 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
1115
          try {
1116 1
            std::vector<Boxed_Value> vec;
1117 1
            if (!this->children.empty()) {
1118 1
              vec.reserve(this->children[0]->children.size());
1119 1
              for (const auto &child : this->children[0]->children) {
1120 1
                vec.push_back(detail::clone_if_necessary(child->eval(t_ss), m_loc, t_ss));
1121
              }
1122
            }
1123 1
            return const_var(std::move(vec));
1124
          }
1125 1
          catch (const exception::dispatch_error &) {
1126 1
            throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements");
1127
          }
1128
        }
1129

1130
      private:
1131
        mutable std::atomic_uint_fast32_t m_loc = {0};
1132
    };
1133

1134
    template<typename T>
1135
    struct Inline_Map_AST_Node final : AST_Node_Impl<T> {
1136 1
        Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1137 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { }
1138

1139 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
1140
        {
1141
          try {
1142 1
            std::map<std::string, Boxed_Value> retval;
1143

1144 1
            for (const auto &child : this->children[0]->children) {
1145 1
              retval.insert(std::make_pair(t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss)), 
1146 1
                            detail::clone_if_necessary(child->children[1]->eval(t_ss), m_loc, t_ss)));
1147
            }
1148

1149 1
            return const_var(std::move(retval));
1150
          }
1151 0
          catch (const exception::dispatch_error &e) {
1152 0
            throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss);
1153
          }
1154
        }
1155

1156
      private:
1157
        mutable std::atomic_uint_fast32_t m_loc = {0};
1158
    };
1159

1160
    template<typename T>
1161
    struct Return_AST_Node final : AST_Node_Impl<T> {
1162 1
        Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1163 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { }
1164

1165 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
1166 1
          if (!this->children.empty()) {
1167 1
            throw detail::Return_Value{this->children[0]->eval(t_ss)};
1168
          }
1169
          else {
1170 1
            throw detail::Return_Value{void_var()};
1171
          }
1172
        }
1173
    };
1174

1175
    template<typename T>
1176
    struct File_AST_Node final : AST_Node_Impl<T> {
1177 1
        File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1178 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { }
1179

1180 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
1181
          try {
1182 1
            const auto num_children = this->children.size();
1183

1184 1
            if (num_children > 0) {
1185 1
              for (size_t i = 0; i < num_children-1; ++i) {
1186 1
                this->children[i]->eval(t_ss);
1187
              }
1188 1
              return this->children.back()->eval(t_ss);
1189
            } else {
1190 1
              return void_var();
1191
            }
1192 1
          } catch (const detail::Continue_Loop &) {
1193 1
            throw exception::eval_error("Unexpected `continue` statement outside of a loop");
1194 1
          } catch (const detail::Break_Loop &) {
1195 1
            throw exception::eval_error("Unexpected `break` statement outside of a loop");
1196
          }
1197
        }
1198
    };
1199

1200
    template<typename T>
1201
    struct Reference_AST_Node final : AST_Node_Impl<T> {
1202 1
        Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1203 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children))
1204
        { assert(this->children.size() == 1); }
1205

1206 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
1207 1
          Boxed_Value bv;
1208 1
          t_ss.add_object(this->children[0]->text, bv);
1209 1
          return bv;
1210
        }
1211
    };
1212

1213
    template<typename T>
1214
    struct Prefix_AST_Node final : AST_Node_Impl<T> {
1215 1
        Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1216 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)),
1217 1
          m_oper(Operators::to_operator(this->text, true))
1218 1
        { }
1219

1220 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
1221 1
          Boxed_Value bv(this->children[0]->eval(t_ss));
1222

1223
          try {
1224
            // short circuit arithmetic operations
1225 1
            if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic())
1226
            {
1227 1
              if ((m_oper == Operators::Opers::pre_increment || m_oper == Operators::Opers::pre_decrement) && bv.is_const())
1228
              {
1229 1
                throw exception::eval_error("Error with prefix operator evaluation: cannot modify constant value.");
1230
              }
1231 1
              return Boxed_Number::do_oper(m_oper, bv);
1232
            } else {
1233 1
              chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
1234 1
              fpp.save_params(Function_Params{bv});
1235 1
              return t_ss->call_function(this->text, m_loc, Function_Params{bv}, t_ss.conversions());
1236
            }
1237 1
          } catch (const exception::dispatch_error &e) {
1238 1
            throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
1239
          }
1240
        }
1241

1242
      private:
1243
        Operators::Opers m_oper = Operators::Opers::invalid;
1244
        mutable std::atomic_uint_fast32_t m_loc = {0};
1245
    };
1246

1247
    template<typename T>
1248
    struct Break_AST_Node final : AST_Node_Impl<T> {
1249 1
        Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1250 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { }
1251

1252 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
1253 1
          throw detail::Break_Loop();
1254
        }
1255
    };
1256

1257
    template<typename T>
1258
    struct Continue_AST_Node final : AST_Node_Impl<T> {
1259 1
        Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1260 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { }
1261

1262 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
1263 1
          throw detail::Continue_Loop();
1264
        }
1265
    };
1266

1267
    template<typename T>
1268
    struct Noop_AST_Node final : AST_Node_Impl<T> {
1269 1
        Noop_AST_Node() :
1270 1
          AST_Node_Impl<T>("", AST_Node_Type::Noop, Parse_Location())
1271 1
        { }
1272

1273 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{
1274
          // It's a no-op, that evaluates to "void"
1275 1
          return val;
1276
        }
1277

1278
        Boxed_Value val = void_var();
1279
    };
1280

1281
    template<typename T>
1282
    struct Map_Pair_AST_Node final : AST_Node_Impl<T> {
1283 1
        Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1284 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { }
1285
    };
1286

1287
    template<typename T>
1288
    struct Value_Range_AST_Node final : AST_Node_Impl<T> {
1289 1
        Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1290 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { }
1291
    };
1292

1293
    template<typename T>
1294
    struct Inline_Range_AST_Node final : AST_Node_Impl<T> {
1295 1
        Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1296 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { }
1297

1298 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
1299
          try {
1300 1
            std::array<Boxed_Value, 2> params{
1301 1
              this->children[0]->children[0]->children[0]->eval(t_ss),
1302 1
              this->children[0]->children[0]->children[1]->eval(t_ss)
1303
            };
1304

1305 1
            return t_ss->call_function("generate_range", m_loc, Function_Params{params}, t_ss.conversions());
1306
          }
1307 0
          catch (const exception::dispatch_error &e) {
1308 0
            throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
1309
          }
1310
        }
1311

1312
      private:
1313
        mutable std::atomic_uint_fast32_t m_loc = {0};
1314
    };
1315

1316
    template<typename T>
1317
    struct Try_AST_Node final : AST_Node_Impl<T> {
1318 1
        Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1319 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { }
1320

1321 1
        Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const
1322
        {
1323 1
          Boxed_Value retval;
1324

1325 1
          size_t end_point = this->children.size();
1326 1
          if (this->children.back()->identifier == AST_Node_Type::Finally) {
1327 0
            assert(end_point > 0);
1328 1
            end_point = this->children.size() - 1;
1329
          }
1330 1
          for (size_t i = 1; i < end_point; ++i) {
1331 1
            chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss);
1332 1
            auto &catch_block = *this->children[i];
1333

1334 1
            if (catch_block.children.size() == 1) {
1335
              //No variable capture
1336 0
              retval = catch_block.children[0]->eval(t_ss);
1337 0
              break;
1338 0
            } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) {
1339 1
              const auto name = Arg_List_AST_Node<T>::get_arg_name(*catch_block.children[0]);
1340

1341 1
              if (dispatch::Param_Types(
1342 1
                    std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)}
1343 1
                    ).match(Function_Params{t_except}, t_ss.conversions()).first)
1344
              {
1345 1
                t_ss.add_object(name, t_except);
1346

1347 1
                if (catch_block.children.size() == 2) {
1348
                  //Variable capture
1349 1
                  retval = catch_block.children[1]->eval(t_ss);
1350 1
                  break;
1351
                }
1352
              }
1353
            }
1354
            else {
1355 0
              if (this->children.back()->identifier == AST_Node_Type::Finally) {
1356 0
                this->children.back()->children[0]->eval(t_ss);
1357
              }
1358 0
              throw exception::eval_error("Internal error: catch block size unrecognized");
1359
            }
1360
          }
1361

1362 1
          return retval;
1363
        }
1364

1365 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
1366 1
          Boxed_Value retval;
1367

1368 1
          chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
1369

1370

1371
          try {
1372 1
            retval = this->children[0]->eval(t_ss);
1373
          }
1374 1
          catch (const exception::eval_error &e) {
1375 1
            retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
1376
          }
1377 1
          catch (const std::runtime_error &e) {
1378 1
            retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
1379
          }
1380 1
          catch (const std::out_of_range &e) {
1381 1
            retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
1382
          }
1383 0
          catch (const std::exception &e) {
1384 0
            retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
1385
          }
1386 1
          catch (Boxed_Value &e) {
1387 1
            retval = handle_exception(t_ss, e);
1388
          }
1389 1
          catch (...) {
1390 1
            if (this->children.back()->identifier == AST_Node_Type::Finally) {
1391 1
              this->children.back()->children[0]->eval(t_ss);
1392
            }
1393 1
            throw;
1394
          }
1395

1396

1397 1
          if (this->children.back()->identifier == AST_Node_Type::Finally) {
1398 1
            retval = this->children.back()->children[0]->eval(t_ss);
1399
          }
1400

1401 1
          return retval;
1402
        }
1403

1404
    };
1405

1406
    template<typename T>
1407
    struct Catch_AST_Node final : AST_Node_Impl<T> {
1408 1
        Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1409 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { }
1410
    };
1411

1412
    template<typename T>
1413
    struct Finally_AST_Node final : AST_Node_Impl<T> {
1414 1
        Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1415 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { }
1416
    };
1417

1418
    template<typename T>
1419
    struct Method_AST_Node final : AST_Node_Impl<T> {
1420
        std::shared_ptr<AST_Node_Impl<T>> m_body_node;
1421
        std::shared_ptr<AST_Node_Impl<T>> m_guard_node;
1422

1423 1
        Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1424 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc),
1425
              std::vector<AST_Node_Impl_Ptr<T>>(std::make_move_iterator(t_children.begin()),
1426 1
                                                std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node<T>::has_guard(t_children, 1)?2:1)))
1427
              ),
1428 1
            m_body_node(Def_AST_Node<T>::get_body_node(std::move(t_children))),
1429 1
            m_guard_node(Def_AST_Node<T>::get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2))
1430
          {
1431
          }
1432

1433 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
1434

1435 1
          AST_Node_Impl_Ptr<T> guardnode;
1436

1437 1
          const std::string & class_name = this->children[0]->text;
1438

1439
          //The first param of a method is always the implied this ptr.
1440 1
          std::vector<std::string> t_param_names{"this"};
1441 1
          dispatch::Param_Types param_types;
1442

1443 1
          if ((this->children.size() > 2) 
1444 1
               && (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
1445 1
            auto args = Arg_List_AST_Node<T>::get_arg_names(*this->children[2]);
1446 1
            t_param_names.insert(t_param_names.end(), args.begin(), args.end());
1447 1
            param_types = Arg_List_AST_Node<T>::get_arg_types(*this->children[2], t_ss);
1448
          }
1449

1450 1
          const size_t numparams = t_param_names.size();
1451

1452 1
          std::shared_ptr<dispatch::Proxy_Function_Base> guard;
1453 1
          std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
1454 1
          if (m_guard_node) {
1455 1
            guard = dispatch::make_dynamic_proxy_function(
1456 1
                [engine, t_param_names, guardnode = m_guard_node](const Function_Params &t_params) {
1457
                  return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params);
1458
                }, 
1459 1
                static_cast<int>(numparams), m_guard_node);
1460
          }
1461

1462
          try {
1463 1
            const std::string & function_name = this->children[1]->text;
1464

1465 1
            if (function_name == class_name) {
1466 1
              param_types.push_front(class_name, Type_Info());
1467

1468 1
              t_ss->add(
1469
                  std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
1470
                    dispatch::make_dynamic_proxy_function(
1471 1
                        [engine, t_param_names, node = m_body_node](const Function_Params &t_params) {
1472
                          return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
1473
                        },
1474 1
                        static_cast<int>(numparams), m_body_node, param_types, guard
1475
                      )
1476
                    ),
1477
                  function_name);
1478

1479
            } else {
1480
              // if the type is unknown, then this generates a function that looks up the type
1481
              // at runtime. Defining the type first before this is called is better
1482 1
              auto type = t_ss->get_type(class_name, false);
1483 1
              param_types.push_front(class_name, type);
1484

1485 1
              t_ss->add(
1486
                  std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
1487
                    dispatch::make_dynamic_proxy_function(
1488 1
                      [engine, t_param_names, node = m_body_node](const Function_Params &t_params) {
1489
                        return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
1490
                      },
1491 1
                      static_cast<int>(numparams), m_body_node, param_types, guard), type), 
1492
                  function_name);
1493
            }
1494 1
          } catch (const exception::name_conflict_error &e) {
1495 1
            throw exception::eval_error("Method redefined '" + e.name() + "'");
1496
          }
1497 1
          return void_var();
1498
        }
1499

1500
    };
1501

1502
    template<typename T>
1503
    struct Attr_Decl_AST_Node final : AST_Node_Impl<T> {
1504 1
        Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1505 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { }
1506

1507 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override 
1508
        {
1509 1
          std::string class_name = this->children[0]->text;
1510

1511
          try {
1512 1
            std::string attr_name = this->children[1]->text;
1513

1514 1
            t_ss->add(
1515
                std::make_shared<dispatch::detail::Dynamic_Object_Function>(
1516 1
                     std::move(class_name),
1517
                     fun([attr_name](dispatch::Dynamic_Object &t_obj) {
1518
                           return t_obj.get_attr(attr_name);
1519
                         }),
1520 1
                     true
1521

1522 1
                ), this->children[1]->text);
1523 1
          } catch (const exception::name_conflict_error &e) {
1524 1
            throw exception::eval_error("Attribute redefined '" + e.name() + "'");
1525
          }
1526 1
          return void_var();
1527
        }
1528

1529
    };
1530

1531

1532
    template<typename T>
1533
    struct Logical_And_AST_Node final : AST_Node_Impl<T> {
1534 1
        Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1535 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children)) 
1536
        { assert(this->children.size() == 2); }
1537

1538 1
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
1539
        {
1540 1
          return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
1541 1
              && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
1542
        }
1543

1544
    };
1545

1546
    template<typename T>
1547
    struct Logical_Or_AST_Node final : AST_Node_Impl<T> {
1548 1
        Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_Node_Impl_Ptr<T>> t_children) :
1549 1
          AST_Node_Impl<T>(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) 
1550
        { assert(this->children.size() == 2); }
1551

1552
        Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
1553
        {
1554
          return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)
1555
              || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss));
1556
        }
1557
    };
1558
  }
1559

1560

1561
}
1562
#endif /* CHAISCRIPT_EVAL_HPP_ */
1563

Read our documentation on viewing source code .

Loading