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_COMMON_HPP_
12
#define CHAISCRIPT_COMMON_HPP_
13

14
#include <algorithm>
15
#include <memory>
16
#include <sstream>
17
#include <stdexcept>
18
#include <string>
19
#include <vector>
20

21
#include "../chaiscript_defines.hpp"
22
#include "../dispatchkit/boxed_value.hpp"
23
#include "../dispatchkit/dispatchkit.hpp"
24
#include "../dispatchkit/proxy_functions.hpp"
25
#include "../dispatchkit/type_info.hpp"
26
#include <unordered_set>
27

28
namespace chaiscript {
29
struct AST_Node;
30
}  // namespace chaiscript
31

32
namespace chaiscript
33
{
34
  struct Name_Validator {
35
    template<typename T>
36 1
    static bool is_reserved_word(const T &s) noexcept
37
    {
38 1
      const static std::unordered_set<std::uint32_t> words{
39
        utility::hash("def"),
40
        utility::hash("fun"), 
41
        utility::hash("while"),
42
        utility::hash("for"),
43
        utility::hash("if"),
44
        utility::hash("else"),
45
        utility::hash("&&"),
46
        utility::hash("||"),
47
        utility::hash(","),
48
        utility::hash("auto"),
49
        utility::hash("return"),
50
        utility::hash("break"),
51
        utility::hash("true"),
52
        utility::hash("false"),
53
        utility::hash("class"),
54
        utility::hash("attr"),
55
        utility::hash("var"),
56
        utility::hash("global"),
57
        utility::hash("GLOBAL"),
58
        utility::hash("_"),
59
        utility::hash("__LINE__"),
60
        utility::hash("__FILE__"),
61
        utility::hash("__FUNC__"),
62
        utility::hash("__CLASS__")};
63

64 1
      return words.count(utility::hash(s)) == 1;
65
    }
66

67
    template<typename T>
68 1
    static bool valid_object_name(const T &name) noexcept
69
    {
70 1
      return name.find("::") == std::string::npos && !is_reserved_word(name);
71
    }
72

73
    template<typename T>
74 1
    static void validate_object_name(const T &name)
75
    {
76 1
      if (is_reserved_word(name)) {
77 0
        throw exception::reserved_word_error(std::string(name));
78
      }
79

80 1
      if (name.find("::") != std::string::npos) {
81 0
        throw exception::illegal_name_error(std::string(name));
82
      }
83
    }
84
  };
85

86
  /// Signature of module entry point that all binary loadable modules must implement.
87
  using Create_Module_Func = ModulePtr (*)();
88

89

90
  /// Types of AST nodes available to the parser and eval
91
  enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl, Assign_Decl,
92
    Array_Call, Dot_Access,
93
    Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
94
    Inline_Range, Try, Catch, Finally, Method, Attr_Decl,  
95
    Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
96
  };
97

98
  enum class Operator_Precedence { Ternary_Cond, Logical_Or, 
99
    Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And, 
100
    Equality, Comparison, Shift, Addition, Multiplication, Prefix };
101

102
  namespace
103
  {
104
    /// Helper lookup to get the name of each node type
105 0
    constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
106 0
      constexpr const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl",
107
                                    "Array_Call", "Dot_Access", 
108
                                    "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
109
                                    "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
110
                                    "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
111

112 0
      return ast_node_types[static_cast<int>(ast_node_type)];
113
    }
114
  }
115

116
  /// \brief Convenience type for file positions
117
  struct File_Position {
118
    int line = 0;
119
    int column = 0;
120

121 1
    constexpr File_Position(int t_file_line, int t_file_column) noexcept
122 1
      : line(t_file_line), column(t_file_column) { }
123

124 1
    constexpr File_Position() noexcept = default;
125
  };
126

127
  struct Parse_Location {
128 1
    Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
129
        const int t_end_line=0, const int t_end_col=0)
130 1
      : start(t_start_line, t_start_col), 
131
        end(t_end_line, t_end_col),
132 1
        filename(std::make_shared<std::string>(std::move(t_fname)))
133
    {
134
    }
135

136 1
    Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
137
        const int t_end_line=0, const int t_end_col=0)
138 1
      : start(t_start_line, t_start_col), 
139
        end(t_end_line, t_end_col),
140 1
        filename(std::move(t_fname))
141
    {
142
    }
143

144

145

146
    File_Position start;
147
    File_Position end;
148
    std::shared_ptr<std::string> filename;
149
  };
150

151

152
  /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
153
  using AST_NodePtr = std::unique_ptr<AST_Node>;
154
  using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
155

156
  struct AST_Node_Trace;
157

158

159
  /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
160
  namespace exception
161
  {
162
    /// \brief Thrown if an error occurs while attempting to load a binary module
163
    struct load_module_error : std::runtime_error
164
    {
165 1
      explicit load_module_error(const std::string &t_reason)
166 1
        : std::runtime_error(t_reason)
167
      {
168
      }
169

170 1
      load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
171 1
        : std::runtime_error(format_error(t_name, t_errors))
172
      {
173
      }
174

175 1
      load_module_error(const load_module_error &) = default;
176 1
      ~load_module_error() noexcept override = default;
177

178 1
      static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
179
      {
180 1
        std::stringstream ss;
181
        ss << "Error loading module '" << t_name << "'\n"
182 1
           << "  The following locations were searched:\n";
183

184 1
        for (const auto &err : t_errors) {
185 1
          ss << "    " << err.what() << "\n";
186
        }
187

188 1
        return ss.str();
189
      }
190
    };
191

192

193
    /// Errors generated during parsing or evaluation
194
    struct eval_error : std::runtime_error {
195
      std::string reason;
196
      File_Position start_position;
197
      std::string filename;
198
      std::string detail;
199
      std::vector<AST_Node_Trace> call_stack;
200

201
      eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
202
          const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
203
          bool t_dot_notation,
204
          const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
205
        std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
206
        reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss)) 
207
      {}
208

209 1
      eval_error(const std::string &t_why, 
210
           const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
211
           bool t_dot_notation,
212 1
           const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
213 1
        std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
214 1
        reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
215 1
      {}
216

217

218 1
      eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept :
219 1
        std::runtime_error(format(t_why, t_where, t_fname)),
220 1
        reason(t_why), start_position(t_where), filename(t_fname)
221 1
      {}
222

223 1
      explicit eval_error(const std::string &t_why) noexcept
224 1
        : std::runtime_error("Error: \"" + t_why + "\" "),
225 1
        reason(t_why) 
226 1
      {}
227

228 1
      eval_error(const eval_error &) = default;
229

230 1
      std::string pretty_print() const
231
      {
232 1
        std::ostringstream ss;
233

234 1
        ss << what();
235 1
        if (!call_stack.empty()) {
236 1
          ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
237 1
          ss << '\n' << detail << '\n';
238 1
          ss << "  " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
239 1
          for (size_t j = 1; j < call_stack.size(); ++j) {
240 1
            if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
241 1
                && id(call_stack[j]) != chaiscript::AST_Node_Type::File)
242
            {
243 1
              ss << '\n';
244 1
              ss << "  from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
245
            }
246
          }
247
        }
248 1
        ss << '\n';
249 1
        return ss.str();
250
      }
251

252 1
      ~eval_error() noexcept override = default;
253

254
    private:
255

256
      template<typename T>
257 1
        static AST_Node_Type id(const T& t) noexcept
258
        {
259 1
          return t.identifier;
260
        }
261

262
      template<typename T>
263 1
        static std::string pretty(const T& t)
264
        {
265 1
          return t.pretty_print();
266
        }
267

268
      template<typename T>
269 1
        static const std::string &fname(const T& t) noexcept
270
        {
271 1
          return t.filename();
272
        }
273

274
      template<typename T>
275 1
        static std::string startpos(const T& t)
276
        {
277 1
          std::ostringstream oss;
278 1
          oss << t.start().line << ", " << t.start().column;
279 1
          return oss.str();
280
        }
281

282 1
      static std::string format_why(const std::string &t_why)
283
      {
284 1
        return "Error: \"" + t_why + "\"";
285
      }
286

287 1
      static std::string format_types(const Const_Proxy_Function &t_func,
288
          bool t_dot_notation,
289
          const chaiscript::detail::Dispatch_Engine &t_ss)
290
      {
291 0
        assert(t_func);
292 1
        int arity = t_func->get_arity();
293 1
        std::vector<Type_Info> types = t_func->get_param_types();
294

295 1
        std::string retval;
296 1
        if (arity == -1)
297
        {
298 1
          retval = "(...)";
299 1
          if (t_dot_notation)
300
          {
301 1
            retval = "(Object)." + retval;
302
          }
303 1
        } else if (types.size() <= 1) {
304 1
          retval = "()";
305
        } else {
306 1
          std::stringstream ss;
307 1
          ss << "(";
308

309 1
          std::string paramstr;
310

311 1
          for (size_t index = 1;
312 1
               index != types.size();
313
               ++index)
314
          {
315 1
            paramstr += (types[index].is_const()?"const ":"");
316 1
            paramstr += t_ss.get_type_name(types[index]);
317

318 1
            if (index == 1 && t_dot_notation)
319
            {
320 1
              paramstr += ").(";
321 1
              if (types.size() == 2)
322
              {
323 1
                paramstr += ", ";
324
              }
325
            } else {
326 1
              paramstr += ", ";
327
            }
328
          }
329

330 1
          ss << paramstr.substr(0, paramstr.size() - 2);
331

332 1
          ss << ")";
333 1
          retval = ss.str();
334
        }
335

336

337
        std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun 
338 1
          = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
339

340 1
        if (dynfun && dynfun->has_parse_tree())
341
        {
342 1
          Proxy_Function f = dynfun->get_guard();
343

344 1
          if (f)
345
          {
346 1
            auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
347 0
            if (dynfunguard && dynfunguard->has_parse_tree())
348
            {
349 1
              retval += " : " + format_guard(dynfunguard->get_parse_tree());
350
            }
351
          }
352

353 1
          retval += "\n          Defined at " + format_location(dynfun->get_parse_tree());
354
        }
355

356 1
        return retval;
357
      }
358

359
      template<typename T>
360 1
        static std::string format_guard(const T &t)
361
        {
362 1
          return t.pretty_print();
363
        }
364

365
      template<typename T>
366 1
        static std::string format_location(const T &t)
367
        {
368 1
          std::ostringstream oss;
369 1
          oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")"; 
370 1
          return oss.str();
371
        }
372

373 1
      static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
374
          bool t_dot_notation,
375
          const chaiscript::detail::Dispatch_Engine &t_ss)
376
      {
377 1
        std::stringstream ss;
378 1
        if (t_functions.size() == 1)
379
        {
380 0
          assert(t_functions[0]);
381 1
          ss << "  Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
382
        } else {
383 1
          ss << "  " << t_functions.size() << " overloads available:\n";
384

385 1
          for (const auto & t_function : t_functions)
386
          {
387 1
            ss << "      " << format_types((t_function), t_dot_notation, t_ss) << '\n';
388
          }
389

390
        }
391

392 1
        return ss.str();
393

394
      }
395

396 1
      static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
397
          bool t_dot_notation,
398
          const chaiscript::detail::Dispatch_Engine &t_ss)
399
      {
400 1
        std::stringstream ss;
401 1
        ss << "(";
402

403 1
        if (!t_parameters.empty())
404
        {
405 1
          std::string paramstr;
406

407 1
          for (auto itr = t_parameters.begin();
408 1
               itr != t_parameters.end();
409 1
               ++itr)
410
          {
411 1
            paramstr += (itr->is_const()?"const ":"");
412 1
            paramstr += t_ss.type_name(*itr);
413

414 1
            if (itr == t_parameters.begin() && t_dot_notation)
415
            {
416 1
              paramstr += ").(";
417 1
              if (t_parameters.size() == 1)
418
              {
419 1
                paramstr += ", ";
420
              }
421
            } else {
422 1
              paramstr += ", ";
423
            }
424
          }
425

426 1
          ss << paramstr.substr(0, paramstr.size() - 2);
427
        }
428 1
        ss << ")";
429

430 1
        return ss.str();
431
      }
432

433 1
      static std::string format_filename(const std::string &t_fname)
434
      {
435 1
        std::stringstream ss;
436

437 1
        if (t_fname != "__EVAL__")
438
        {
439 1
          ss << "in '" << t_fname << "' ";
440
        } else {
441 1
          ss << "during evaluation ";
442
        }
443

444 1
        return ss.str();
445
      }
446

447 1
      static std::string format_location(const File_Position &t_where)
448
      {
449 1
        std::stringstream ss;
450 1
        ss << "at (" << t_where.line << ", " << t_where.column << ")";
451 1
        return ss.str();
452
      }
453

454
      static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
455
          const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
456
      {
457
        std::stringstream ss;
458

459
        ss << format_why(t_why);
460
        ss << " ";
461

462
        ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
463
        ss << " ";
464

465
        ss << format_filename(t_fname);
466
        ss << " ";
467

468
        ss << format_location(t_where);
469

470
        return ss.str();
471
      }
472

473 1
      static std::string format(const std::string &t_why, 
474
          const std::vector<Boxed_Value> &t_parameters, 
475
          bool t_dot_notation,
476
          const chaiscript::detail::Dispatch_Engine &t_ss)
477
      {
478 1
        std::stringstream ss;
479

480 1
        ss << format_why(t_why);
481 1
        ss << " ";
482

483 1
        ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
484 1
        ss << " ";
485

486 1
        return ss.str();
487
      }
488

489 1
      static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
490
      {
491 1
        std::stringstream ss;
492

493 1
        ss << format_why(t_why);
494 1
        ss << " ";
495

496 1
        ss << format_filename(t_fname);
497 1
        ss << " ";
498

499 1
        ss << format_location(t_where);
500

501 1
        return ss.str();
502
      }
503
    };
504

505

506
    /// Errors generated when loading a file
507
    struct file_not_found_error : std::runtime_error {
508 1
      explicit file_not_found_error(const std::string &t_filename)
509 1
        : std::runtime_error("File Not Found: " + t_filename),
510 1
          filename(t_filename)
511 1
      { }
512

513
      file_not_found_error(const file_not_found_error &) = default;
514 1
      ~file_not_found_error() noexcept override = default;
515

516
      std::string filename;
517
    };
518

519
  }
520

521
 
522
  /// \brief Struct that doubles as both a parser ast_node and an AST node.
523
  struct AST_Node {
524
    public:
525
      const AST_Node_Type identifier;
526
      const std::string text;
527
      Parse_Location location;
528

529 1
      const std::string &filename() const noexcept {
530 1
        return *location.filename;
531
      }
532

533 1
      const File_Position &start() const noexcept {
534 1
        return location.start;
535
      }
536

537 0
      const File_Position &end() const noexcept {
538 0
        return location.end;
539
      }
540

541 1
      std::string pretty_print() const
542
      {
543 1
        std::ostringstream oss;
544

545 1
        oss << text;
546

547 1
        for (auto & elem : get_children()) {
548 1
          oss << elem.get().pretty_print() << ' ';
549
        }
550

551 1
        return oss.str();
552
      }
553

554
      virtual std::vector<std::reference_wrapper<AST_Node>> get_children() const = 0;
555
      virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
556

557

558
      /// Prints the contents of an AST node, including its children, recursively
559 0
      std::string to_string(const std::string &t_prepend = "") const {
560 0
        std::ostringstream oss;
561

562 0
        oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
563 0
            << this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
564

565 0
        for (auto & elem : get_children()) {
566 0
          oss << elem.get().to_string(t_prepend + "  ");
567
        }
568 0
        return oss.str();
569
      }
570

571

572 1
      static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
573
        try {
574 1
          return t_ss->boxed_cast<bool>(t_bv);
575
        }
576 1
        catch (const exception::bad_boxed_cast &) {
577 1
          throw exception::eval_error("Condition not boolean");
578
        }
579
      }
580

581

582 1
      virtual ~AST_Node() noexcept = default;
583
      AST_Node(AST_Node &&) = default;
584
      AST_Node &operator=(AST_Node &&) = default;
585
      AST_Node(const AST_Node &) = delete;
586
      AST_Node& operator=(const AST_Node &) = delete;
587

588

589
    protected:
590 1
      AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
591 1
        : identifier(t_id), text(std::move(t_ast_node_text)),
592 1
          location(std::move(t_loc))
593
      {
594
      }
595

596

597
  };
598

599
  struct AST_Node_Trace
600
  {
601
    const AST_Node_Type identifier;
602
    const std::string text;
603
    Parse_Location location;
604

605 1
    const std::string &filename() const noexcept {
606 1
      return *location.filename;
607
    }
608

609 1
    const File_Position &start() const noexcept {
610 1
      return location.start;
611
    }
612

613
    const File_Position &end() const noexcept {
614
      return location.end;
615
    }
616

617 1
    std::string pretty_print() const
618
    {
619 1
      std::ostringstream oss;
620

621 1
      oss << text;
622

623 1
      for (const auto & elem : children) {
624 1
        oss << elem.pretty_print() << ' ';
625
      }
626

627 1
      return oss.str();
628
    }
629

630 1
    std::vector<AST_Node_Trace> get_children(const AST_Node &node)
631
    {
632 1
      const auto node_children = node.get_children();
633 1
      return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
634
    }
635

636 1
    AST_Node_Trace(const AST_Node &node)
637 1
      : identifier(node.identifier), text(node.text),
638 1
      location(node.location), children(get_children(node))
639
    {
640
    }
641

642

643
    std::vector<AST_Node_Trace> children;
644

645
  };
646

647
  namespace parser {
648
    class ChaiScript_Parser_Base
649
    {
650
      public:
651
        virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
652
        virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
653
        virtual void *get_tracer_ptr() = 0;
654 1
        virtual ~ChaiScript_Parser_Base() = default;
655 1
        ChaiScript_Parser_Base() = default;
656
        ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
657
        ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
658
        ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
659

660
        template<typename T>
661 1
        T &get_tracer() noexcept
662
        {
663
          // to do type check this somehow?
664 1
          return *static_cast<T*>(get_tracer_ptr());
665
        }
666

667
      protected:
668
        ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
669
    };
670
  }
671

672
  namespace eval
673
  {
674
    namespace detail
675
    {
676
      /// Special type for returned values
677
      struct Return_Value {
678
        Boxed_Value retval;
679
      };
680

681

682
      /// Special type indicating a call to 'break'
683
      struct Break_Loop {
684
      };
685

686

687
      /// Special type indicating a call to 'continue'
688
      struct Continue_Loop {
689
      };
690

691

692
      /// Creates a new scope then pops it on destruction
693
      struct Scope_Push_Pop
694
      {
695
        Scope_Push_Pop(Scope_Push_Pop &&) = default;
696
        Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
697
        Scope_Push_Pop(const Scope_Push_Pop &) = delete;
698
        Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
699

700 1
        explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
701 1
          : m_ds(t_ds)
702
        {
703 1
          m_ds->new_scope(m_ds.stack_holder());
704
        }
705

706 1
        ~Scope_Push_Pop()
707
        {
708 1
          m_ds->pop_scope(m_ds.stack_holder());
709
        }
710

711

712
        private:
713
          const chaiscript::detail::Dispatch_State &m_ds;
714
      };
715

716
      /// Creates a new function call and pops it on destruction
717
      struct Function_Push_Pop
718
      {
719
        Function_Push_Pop(Function_Push_Pop &&) = default;
720
        Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
721
        Function_Push_Pop(const Function_Push_Pop &) = delete;
722
        Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
723

724 1
        explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
725 1
          : m_ds(t_ds)
726
        {
727 1
          m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
728
        }
729

730 1
        ~Function_Push_Pop()
731
        {
732 1
          m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
733
        }
734

735 1
        void save_params(const Function_Params &t_params)
736
        {
737 1
          m_ds->save_function_params(t_params);
738
        }
739

740

741
        private:
742
          const chaiscript::detail::Dispatch_State &m_ds;
743
      };
744

745
      /// Creates a new scope then pops it on destruction
746
      struct Stack_Push_Pop
747
      {
748
        Stack_Push_Pop(Stack_Push_Pop &&) = default;
749
        Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
750
        Stack_Push_Pop(const Stack_Push_Pop &) = delete;
751
        Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
752

753 1
        explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
754 1
          : m_ds(t_ds)
755
        {
756 1
          m_ds->new_stack(m_ds.stack_holder());
757
        }
758

759 1
        ~Stack_Push_Pop()
760
        {
761 1
          m_ds->pop_stack(m_ds.stack_holder());
762
        }
763

764

765
        private:
766
          const chaiscript::detail::Dispatch_State &m_ds;
767
      };
768
    }
769
  }
770
}
771

772
#endif /* _CHAISCRIPT_COMMON_HPP */
773

Read our documentation on viewing source code .

Loading