Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / lua / actions.cpp
blob3dcbe9549f09d4772d422bd9a0e18546b538d494
1 #include "lua/internal.hpp"
2 #include "interface/romtype.hpp"
3 #include "core/instance.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/messages.hpp"
6 #include "core/rom.hpp"
8 namespace
10 int action(lua::state& L, lua::parameters& P)
12 auto& core = CORE();
13 std::string name;
15 P(name);
17 const interface_action* act = NULL;
18 for(auto i : core.rom->get_actions())
19 if(i->get_symbol() == name) {
20 act = i;
21 break;
23 if(!act)
24 throw std::runtime_error("No such action");
25 if(!(core.rom->action_flags(act->id) & 1))
26 throw std::runtime_error("Action not enabled.");
27 std::vector<interface_action_paramval> params;
28 for(auto i : act->params) {
29 regex_results r;
30 interface_action_paramval pv;
31 if(r = regex("string(:(.*))?", i.model)) {
32 P(pv.s);
33 bool bad = false;;
34 try {
35 if(r[2] != "" && !regex_match(r[2], pv.s))
36 bad = true;
37 } catch(...) {
38 messages << "Internal error: Bad constraint in '" << i.model << "'."
39 << std::endl;
40 throw std::runtime_error("Internal error");
42 if(bad)
43 throw std::runtime_error("String does not satisfy constraints.");
44 } else if(r = regex("int:([0-9]+),([0-9]+)", i.model)) {
45 int64_t low, high;
46 try {
47 low = parse_value<int64_t>(r[1]);
48 high = parse_value<int64_t>(r[2]);
49 } catch(...) {
50 messages << "Internal error: Unknown limits in '" << i.model << "'."
51 << std::endl;
52 throw std::runtime_error("Internal error");
54 P(pv.i);
55 if(pv.i < low || pv.i > high) {
56 throw std::runtime_error("Parameter out of limits.");
58 } else if(r = regex("enum:(.*)", i.model)) {
59 std::string p;
60 P(p);
61 unsigned num = 0;
62 try {
63 JSON::node e(r[1]);
64 for(auto i2 : e) {
65 std::string n;
66 if(i2.type() == JSON::string)
67 n = i2.as_string8();
68 else if(i2.type() == JSON::array)
69 n = i2.index(0).as_string8();
70 else
71 throw std::runtime_error("Choice not array nor "
72 "string");
73 if(n == p)
74 goto out;
75 num++;
77 } catch(std::exception& e) {
78 messages << "JSON parse error parsing " << "model: "
79 << e.what() << std::endl;
80 throw std::runtime_error("Internal error");
82 throw std::runtime_error("Invalid choice for enumeration.");
83 out:
84 pv.i = num;
85 } else if(regex_match("bool", i.model)) {
86 P(pv.b);
87 } else if(regex_match("toggle", i.model)) {
88 } else {
89 messages << "Internal error: Unknown parameter model '" << i.model << "'."
90 << std::endl;
91 throw std::runtime_error("Internal error");
93 params.push_back(pv);
95 if(P.more())
96 throw std::runtime_error("Excess arguments for action");
97 core.rom->execute_action(act->id, params);
98 return 0;
101 int action_flags(lua::state& L, lua::parameters& P)
103 auto& core = CORE();
104 std::string name;
106 P(name);
108 const interface_action* act = NULL;
109 for(auto i : core.rom->get_actions())
110 if(i->get_symbol() == name) {
111 act = i;
112 break;
114 if(!act)
115 throw std::runtime_error("No such action");
116 L.pushnumber(core.rom->action_flags(act->id));
117 return 1;
120 lua::functions LUA_actions_fns(lua_func_misc, "memory", {
121 {"action", action},
122 {"action_flags", action_flags},