chaiscript_common.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. // This file is distributed under the BSD License.
  2. // See "license.txt" for details.
  3. // Copyright 2009-2012, Jonathan Turner ([email protected])
  4. // Copyright 2009-2017, Jason Turner ([email protected])
  5. // http://www.chaiscript.com
  6. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
  7. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
  8. #ifndef CHAISCRIPT_COMMON_HPP_
  9. #define CHAISCRIPT_COMMON_HPP_
  10. #include <algorithm>
  11. #include <memory>
  12. #include <sstream>
  13. #include <stdexcept>
  14. #include <string>
  15. #include <vector>
  16. #include "../chaiscript_defines.hpp"
  17. #include "../dispatchkit/boxed_value.hpp"
  18. #include "../dispatchkit/dispatchkit.hpp"
  19. #include "../dispatchkit/proxy_functions.hpp"
  20. #include "../dispatchkit/type_info.hpp"
  21. namespace chaiscript {
  22. struct AST_Node;
  23. } // namespace chaiscript
  24. namespace chaiscript
  25. {
  26. struct Name_Validator {
  27. static bool is_reserved_word(const std::string &name)
  28. {
  29. static const std::set<std::string> m_reserved_words
  30. = {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
  31. "return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
  32. "__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
  33. return m_reserved_words.count(name) > 0;
  34. }
  35. static bool valid_object_name(const std::string &name)
  36. {
  37. return name.find("::") == std::string::npos && !is_reserved_word(name);
  38. }
  39. static void validate_object_name(const std::string &name)
  40. {
  41. if (is_reserved_word(name)) {
  42. throw exception::reserved_word_error(name);
  43. }
  44. if (name.find("::") != std::string::npos) {
  45. throw exception::illegal_name_error(name);
  46. }
  47. }
  48. };
  49. /// Signature of module entry point that all binary loadable modules must implement.
  50. typedef ModulePtr (*Create_Module_Func)();
  51. /// Types of AST nodes available to the parser and eval
  52. enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl,
  53. Array_Call, Dot_Access,
  54. Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
  55. Inline_Range, Try, Catch, Finally, Method, Attr_Decl,
  56. Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
  57. };
  58. enum class Operator_Precidence { Ternary_Cond, Logical_Or,
  59. Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
  60. Equality, Comparison, Shift, Addition, Multiplication, Prefix };
  61. namespace
  62. {
  63. /// Helper lookup to get the name of each node type
  64. inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
  65. static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl",
  66. "Array_Call", "Dot_Access",
  67. "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
  68. "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
  69. "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
  70. return ast_node_types[static_cast<int>(ast_node_type)];
  71. }
  72. }
  73. /// \brief Convenience type for file positions
  74. struct File_Position {
  75. int line;
  76. int column;
  77. File_Position(int t_file_line, int t_file_column)
  78. : line(t_file_line), column(t_file_column) { }
  79. File_Position() : line(0), column(0) { }
  80. };
  81. struct Parse_Location {
  82. Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
  83. const int t_end_line=0, const int t_end_col=0)
  84. : start(t_start_line, t_start_col),
  85. end(t_end_line, t_end_col),
  86. filename(std::make_shared<std::string>(std::move(t_fname)))
  87. {
  88. }
  89. Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
  90. const int t_end_line=0, const int t_end_col=0)
  91. : start(t_start_line, t_start_col),
  92. end(t_end_line, t_end_col),
  93. filename(std::move(t_fname))
  94. {
  95. }
  96. File_Position start;
  97. File_Position end;
  98. std::shared_ptr<std::string> filename;
  99. };
  100. /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
  101. typedef std::unique_ptr<AST_Node> AST_NodePtr;
  102. typedef std::unique_ptr<const AST_Node> AST_NodePtr_Const;
  103. struct AST_Node_Trace;
  104. /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
  105. namespace exception
  106. {
  107. /// \brief Thrown if an error occurs while attempting to load a binary module
  108. struct load_module_error : std::runtime_error
  109. {
  110. explicit load_module_error(const std::string &t_reason) noexcept
  111. : std::runtime_error(t_reason)
  112. {
  113. }
  114. load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
  115. : std::runtime_error(format_error(t_name, t_errors))
  116. {
  117. }
  118. load_module_error(const load_module_error &) = default;
  119. ~load_module_error() noexcept override = default;
  120. static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
  121. {
  122. std::stringstream ss;
  123. ss << "Error loading module '" << t_name << "'\n"
  124. << " The following locations were searched:\n";
  125. for (const auto &err : t_errors) {
  126. ss << " " << err.what() << "\n";
  127. }
  128. return ss.str();
  129. }
  130. };
  131. /// Errors generated during parsing or evaluation
  132. struct eval_error : std::runtime_error {
  133. std::string reason;
  134. File_Position start_position;
  135. std::string filename;
  136. std::string detail;
  137. std::vector<AST_Node_Trace> call_stack;
  138. eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
  139. const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
  140. bool t_dot_notation,
  141. const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
  142. std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
  143. reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
  144. {}
  145. eval_error(const std::string &t_why,
  146. const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
  147. bool t_dot_notation,
  148. const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
  149. std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
  150. reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
  151. {}
  152. eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept :
  153. std::runtime_error(format(t_why, t_where, t_fname)),
  154. reason(t_why), start_position(t_where), filename(t_fname)
  155. {}
  156. explicit eval_error(const std::string &t_why) noexcept
  157. : std::runtime_error("Error: \"" + t_why + "\" "),
  158. reason(t_why)
  159. {}
  160. eval_error(const eval_error &) = default;
  161. std::string pretty_print() const
  162. {
  163. std::ostringstream ss;
  164. ss << what();
  165. if (!call_stack.empty()) {
  166. ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
  167. ss << '\n' << detail << '\n';
  168. ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
  169. for (size_t j = 1; j < call_stack.size(); ++j) {
  170. if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
  171. && id(call_stack[j]) != chaiscript::AST_Node_Type::File)
  172. {
  173. ss << '\n';
  174. ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
  175. }
  176. }
  177. }
  178. ss << '\n';
  179. return ss.str();
  180. }
  181. ~eval_error() noexcept override = default;
  182. private:
  183. template<typename T>
  184. static AST_Node_Type id(const T& t)
  185. {
  186. return t.identifier;
  187. }
  188. template<typename T>
  189. static std::string pretty(const T& t)
  190. {
  191. return t.pretty_print();
  192. }
  193. template<typename T>
  194. static const std::string &fname(const T& t)
  195. {
  196. return t.filename();
  197. }
  198. template<typename T>
  199. static std::string startpos(const T& t)
  200. {
  201. std::ostringstream oss;
  202. oss << t.start().line << ", " << t.start().column;
  203. return oss.str();
  204. }
  205. static std::string format_why(const std::string &t_why)
  206. {
  207. return "Error: \"" + t_why + "\"";
  208. }
  209. static std::string format_types(const Const_Proxy_Function &t_func,
  210. bool t_dot_notation,
  211. const chaiscript::detail::Dispatch_Engine &t_ss)
  212. {
  213. assert(t_func);
  214. int arity = t_func->get_arity();
  215. std::vector<Type_Info> types = t_func->get_param_types();
  216. std::string retval;
  217. if (arity == -1)
  218. {
  219. retval = "(...)";
  220. if (t_dot_notation)
  221. {
  222. retval = "(Object)." + retval;
  223. }
  224. } else if (types.size() <= 1) {
  225. retval = "()";
  226. } else {
  227. std::stringstream ss;
  228. ss << "(";
  229. std::string paramstr;
  230. for (size_t index = 1;
  231. index != types.size();
  232. ++index)
  233. {
  234. paramstr += (types[index].is_const()?"const ":"");
  235. paramstr += t_ss.get_type_name(types[index]);
  236. if (index == 1 && t_dot_notation)
  237. {
  238. paramstr += ").(";
  239. if (types.size() == 2)
  240. {
  241. paramstr += ", ";
  242. }
  243. } else {
  244. paramstr += ", ";
  245. }
  246. }
  247. ss << paramstr.substr(0, paramstr.size() - 2);
  248. ss << ")";
  249. retval = ss.str();
  250. }
  251. std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
  252. = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
  253. if (dynfun && dynfun->has_parse_tree())
  254. {
  255. Proxy_Function f = dynfun->get_guard();
  256. if (f)
  257. {
  258. auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
  259. if (dynfunguard && dynfunguard->has_parse_tree())
  260. {
  261. retval += " : " + format_guard(dynfunguard->get_parse_tree());
  262. }
  263. }
  264. retval += "\n Defined at " + format_location(dynfun->get_parse_tree());
  265. }
  266. return retval;
  267. }
  268. template<typename T>
  269. static std::string format_guard(const T &t)
  270. {
  271. return t.pretty_print();
  272. }
  273. template<typename T>
  274. static std::string format_location(const T &t)
  275. {
  276. std::ostringstream oss;
  277. oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")";
  278. return oss.str();
  279. }
  280. static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
  281. bool t_dot_notation,
  282. const chaiscript::detail::Dispatch_Engine &t_ss)
  283. {
  284. std::stringstream ss;
  285. if (t_functions.size() == 1)
  286. {
  287. assert(t_functions[0]);
  288. ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
  289. } else {
  290. ss << " " << t_functions.size() << " overloads available:\n";
  291. for (const auto & t_function : t_functions)
  292. {
  293. ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
  294. }
  295. }
  296. return ss.str();
  297. }
  298. static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
  299. bool t_dot_notation,
  300. const chaiscript::detail::Dispatch_Engine &t_ss)
  301. {
  302. std::stringstream ss;
  303. ss << "(";
  304. if (!t_parameters.empty())
  305. {
  306. std::string paramstr;
  307. for (auto itr = t_parameters.begin();
  308. itr != t_parameters.end();
  309. ++itr)
  310. {
  311. paramstr += (itr->is_const()?"const ":"");
  312. paramstr += t_ss.type_name(*itr);
  313. if (itr == t_parameters.begin() && t_dot_notation)
  314. {
  315. paramstr += ").(";
  316. if (t_parameters.size() == 1)
  317. {
  318. paramstr += ", ";
  319. }
  320. } else {
  321. paramstr += ", ";
  322. }
  323. }
  324. ss << paramstr.substr(0, paramstr.size() - 2);
  325. }
  326. ss << ")";
  327. return ss.str();
  328. }
  329. static std::string format_filename(const std::string &t_fname)
  330. {
  331. std::stringstream ss;
  332. if (t_fname != "__EVAL__")
  333. {
  334. ss << "in '" << t_fname << "' ";
  335. } else {
  336. ss << "during evaluation ";
  337. }
  338. return ss.str();
  339. }
  340. static std::string format_location(const File_Position &t_where)
  341. {
  342. std::stringstream ss;
  343. ss << "at (" << t_where.line << ", " << t_where.column << ")";
  344. return ss.str();
  345. }
  346. static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
  347. const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
  348. {
  349. std::stringstream ss;
  350. ss << format_why(t_why);
  351. ss << " ";
  352. ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
  353. ss << " ";
  354. ss << format_filename(t_fname);
  355. ss << " ";
  356. ss << format_location(t_where);
  357. return ss.str();
  358. }
  359. static std::string format(const std::string &t_why,
  360. const std::vector<Boxed_Value> &t_parameters,
  361. bool t_dot_notation,
  362. const chaiscript::detail::Dispatch_Engine &t_ss)
  363. {
  364. std::stringstream ss;
  365. ss << format_why(t_why);
  366. ss << " ";
  367. ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
  368. ss << " ";
  369. return ss.str();
  370. }
  371. static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
  372. {
  373. std::stringstream ss;
  374. ss << format_why(t_why);
  375. ss << " ";
  376. ss << format_filename(t_fname);
  377. ss << " ";
  378. ss << format_location(t_where);
  379. return ss.str();
  380. }
  381. };
  382. /// Errors generated when loading a file
  383. struct file_not_found_error : std::runtime_error {
  384. explicit file_not_found_error(const std::string &t_filename) noexcept
  385. : std::runtime_error("File Not Found: " + t_filename)
  386. { }
  387. file_not_found_error(const file_not_found_error &) = default;
  388. ~file_not_found_error() noexcept override = default;
  389. };
  390. }
  391. /// \brief Struct that doubles as both a parser ast_node and an AST node.
  392. struct AST_Node {
  393. public:
  394. const AST_Node_Type identifier;
  395. const std::string text;
  396. Parse_Location location;
  397. const std::string &filename() const {
  398. return *location.filename;
  399. }
  400. const File_Position &start() const {
  401. return location.start;
  402. }
  403. const File_Position &end() const {
  404. return location.end;
  405. }
  406. std::string pretty_print() const
  407. {
  408. std::ostringstream oss;
  409. oss << text;
  410. for (auto & elem : get_children()) {
  411. oss << elem.get().pretty_print() << ' ';
  412. }
  413. return oss.str();
  414. }
  415. virtual std::vector<std::reference_wrapper<AST_Node>> get_children() const = 0;
  416. virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
  417. /// Prints the contents of an AST node, including its children, recursively
  418. std::string to_string(const std::string &t_prepend = "") const {
  419. std::ostringstream oss;
  420. oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
  421. << this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
  422. for (auto & elem : get_children()) {
  423. oss << elem.get().to_string(t_prepend + " ");
  424. }
  425. return oss.str();
  426. }
  427. static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
  428. try {
  429. return t_ss->boxed_cast<bool>(t_bv);
  430. }
  431. catch (const exception::bad_boxed_cast &) {
  432. throw exception::eval_error("Condition not boolean");
  433. }
  434. }
  435. virtual ~AST_Node() = default;
  436. AST_Node(AST_Node &&) = default;
  437. AST_Node &operator=(AST_Node &&) = default;
  438. AST_Node(const AST_Node &) = delete;
  439. AST_Node& operator=(const AST_Node &) = delete;
  440. protected:
  441. AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
  442. : identifier(t_id), text(std::move(t_ast_node_text)),
  443. location(std::move(t_loc))
  444. {
  445. }
  446. };
  447. struct AST_Node_Trace
  448. {
  449. const AST_Node_Type identifier;
  450. const std::string text;
  451. Parse_Location location;
  452. const std::string &filename() const {
  453. return *location.filename;
  454. }
  455. const File_Position &start() const {
  456. return location.start;
  457. }
  458. const File_Position &end() const {
  459. return location.end;
  460. }
  461. std::string pretty_print() const
  462. {
  463. std::ostringstream oss;
  464. oss << text;
  465. for (const auto & elem : children) {
  466. oss << elem.pretty_print() << ' ';
  467. }
  468. return oss.str();
  469. }
  470. std::vector<AST_Node_Trace> get_children(const AST_Node &node)
  471. {
  472. const auto node_children = node.get_children();
  473. return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
  474. }
  475. AST_Node_Trace(const AST_Node &node)
  476. : identifier(node.identifier), text(node.text),
  477. location(node.location), children(get_children(node))
  478. {
  479. }
  480. std::vector<AST_Node_Trace> children;
  481. };
  482. namespace parser {
  483. class ChaiScript_Parser_Base
  484. {
  485. public:
  486. virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
  487. virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
  488. virtual void *get_tracer_ptr() = 0;
  489. virtual ~ChaiScript_Parser_Base() = default;
  490. ChaiScript_Parser_Base() = default;
  491. ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
  492. ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
  493. ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
  494. template<typename T>
  495. T &get_tracer()
  496. {
  497. // to do type check this somehow?
  498. return *static_cast<T*>(get_tracer_ptr());
  499. }
  500. protected:
  501. ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
  502. };
  503. }
  504. namespace eval
  505. {
  506. namespace detail
  507. {
  508. /// Special type for returned values
  509. struct Return_Value {
  510. Boxed_Value retval;
  511. explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
  512. };
  513. /// Special type indicating a call to 'break'
  514. struct Break_Loop {
  515. Break_Loop() = default;
  516. };
  517. /// Special type indicating a call to 'continue'
  518. struct Continue_Loop {
  519. Continue_Loop() = default;
  520. };
  521. /// Creates a new scope then pops it on destruction
  522. struct Scope_Push_Pop
  523. {
  524. Scope_Push_Pop(Scope_Push_Pop &&) = default;
  525. Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
  526. Scope_Push_Pop(const Scope_Push_Pop &) = delete;
  527. Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
  528. explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
  529. : m_ds(t_ds)
  530. {
  531. m_ds->new_scope(m_ds.stack_holder());
  532. }
  533. ~Scope_Push_Pop()
  534. {
  535. m_ds->pop_scope(m_ds.stack_holder());
  536. }
  537. private:
  538. const chaiscript::detail::Dispatch_State &m_ds;
  539. };
  540. /// Creates a new function call and pops it on destruction
  541. struct Function_Push_Pop
  542. {
  543. Function_Push_Pop(Function_Push_Pop &&) = default;
  544. Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
  545. Function_Push_Pop(const Function_Push_Pop &) = delete;
  546. Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
  547. explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
  548. : m_ds(t_ds)
  549. {
  550. m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
  551. }
  552. ~Function_Push_Pop()
  553. {
  554. m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
  555. }
  556. void save_params(const std::vector<Boxed_Value> &t_params)
  557. {
  558. m_ds->save_function_params(t_params);
  559. }
  560. void save_params(std::initializer_list<Boxed_Value> t_params)
  561. {
  562. m_ds->save_function_params(t_params);
  563. }
  564. private:
  565. const chaiscript::detail::Dispatch_State &m_ds;
  566. };
  567. /// Creates a new scope then pops it on destruction
  568. struct Stack_Push_Pop
  569. {
  570. Stack_Push_Pop(Stack_Push_Pop &&) = default;
  571. Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
  572. Stack_Push_Pop(const Stack_Push_Pop &) = delete;
  573. Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
  574. explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
  575. : m_ds(t_ds)
  576. {
  577. m_ds->new_stack(m_ds.stack_holder());
  578. }
  579. ~Stack_Push_Pop()
  580. {
  581. m_ds->pop_stack(m_ds.stack_holder());
  582. }
  583. private:
  584. const chaiscript::detail::Dispatch_State &m_ds;
  585. };
  586. }
  587. }
  588. }
  589. #endif /* _CHAISCRIPT_COMMON_HPP */