Revert "Remove Lua 5.1 support"
[lsnes.git] / src / lua / lua.cpp
blobf2aa3141a7d84a14ae7043b363274ebdc749065b
1 #include "core/command.hpp"
2 #include "library/globalwrap.hpp"
3 #include "library/keyboard.hpp"
4 #include "lua/internal.hpp"
5 #include "lua/lua.hpp"
6 #include "lua/unsaferewind.hpp"
7 #include "core/instance.hpp"
8 #include "core/mainloop.hpp"
9 #include "core/messages.hpp"
10 #include "core/memorymanip.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/misc.hpp"
14 #include <map>
15 #include <cstring>
16 #include <string>
17 #include <iostream>
18 extern "C" {
19 #include <lualib.h>
22 extern const char* lua_sysrc_script;
24 lua::function_group lua_func_bit;
25 lua::function_group lua_func_misc;
26 lua::function_group lua_func_load;
27 lua::function_group lua_func_zip;
29 lua::class_group lua_class_callback;
30 lua::class_group lua_class_gui;
31 lua::class_group lua_class_bind;
32 lua::class_group lua_class_pure;
33 lua::class_group lua_class_movie;
34 lua::class_group lua_class_memory;
35 lua::class_group lua_class_fileio;
37 namespace
39 void pushpair(lua::state& L, std::string key, double value)
41 L.pushstring(key.c_str());
42 L.pushnumber(value);
43 L.settable(-3);
46 void pushpair(lua::state& L, std::string key, std::string value)
48 L.pushstring(key.c_str());
49 L.pushstring(value.c_str());
50 L.settable(-3);
53 std::string get_mode_str(int mode)
55 if(mode < 0)
56 return "disabled";
57 else if(mode > 0)
58 return "axis";
59 return "pressure0+";
63 void push_keygroup_parameters(lua::state& L, keyboard::key& p)
65 keyboard::mouse_calibration p2;
66 int mode;
67 L.newtable();
68 switch(p.get_type()) {
69 case keyboard::KBD_KEYTYPE_KEY:
70 pushpair(L, "value", p.get_state());
71 pushpair(L, "type", "key");
72 break;
73 case keyboard::KBD_KEYTYPE_HAT:
74 pushpair(L, "value", p.get_state());
75 pushpair(L, "type", "hat");
76 break;
77 case keyboard::KBD_KEYTYPE_MOUSE:
78 p2 = p.cast_mouse()->get_calibration();
79 pushpair(L, "value", p.get_state());
80 pushpair(L, "type", "mouse");
81 break;
82 case keyboard::KBD_KEYTYPE_AXIS:
83 mode = p.cast_axis()->get_mode();
84 pushpair(L, "value", p.get_state());
85 pushpair(L, "type", get_mode_str(mode));
86 break;
91 namespace
93 int push_keygroup_parameters2(lua::state& L, keyboard::key* p)
95 push_keygroup_parameters(L, *p);
96 return 1;
100 const char* read_lua_fragment(lua_State* L, void* fragment, size_t* size)
102 const char*& luareader_fragment = *reinterpret_cast<const char**>(fragment);
103 if(luareader_fragment) {
104 const char* ret = luareader_fragment;
105 *size = strlen(luareader_fragment);
106 luareader_fragment = NULL;
107 return ret;
108 } else {
109 *size = 0;
110 return NULL;
114 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
116 const char* CONST_eval_sysrc_lua = "local fn = loadstring(" TEMPORARY ", \"<built-in>\"); "
117 "if fn then fn(); else print2(\"Parse error in sysrc.lua script\"); end;";
118 const char* CONST_eval_lua_lua = "local fn = loadstring(" TEMPORARY "); if fn then fn(); else print("
119 "\"Parse error in Lua statement\"); end;";
120 const char* CONST_run_lua_lua = "dofile(" TEMPORARY ");";
122 int system_write_error(lua_State* L)
124 lua_pushstring(L, "_SYSTEM is write-protected");
125 lua_error(L);
126 return 0;
129 void copy_system_tables(lua::state& L)
131 #if LUA_VERSION_NUM == 501
132 L.pushvalue(LUA_GLOBALSINDEX);
133 #endif
134 #if LUA_VERSION_NUM == 502
135 L.rawgeti(LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
136 #endif
137 L.newtable();
138 L.pushnil();
139 while(L.next(-3)) {
140 //Stack: _SYSTEM, KEY, VALUE
141 L.pushvalue(-2);
142 L.pushvalue(-2);
143 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
144 L.rawset(-5);
145 //Stack: _SYSTEM, KEY, VALUE
146 L.pop(1);
147 //Stack: _SYSTEM, KEY
149 L.newtable();
150 L.pushcfunction(system_write_error);
151 L.setfield(-2, "__newindex");
152 L.setmetatable(-2);
153 L.setglobal("_SYSTEM");
157 lua_state::lua_state(lua::state& _L, command::group& _command)
158 : L(_L), command(_command)
160 requests_repaint = false;
161 requests_subframe_paint = false;
162 render_ctx = NULL;
163 input_controllerdata = NULL;
165 idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
166 timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
167 veto_flag = NULL;
168 kill_frame = NULL;
169 hscl = NULL;
170 vscl = NULL;
171 synchronous_paint_ctx = NULL;
172 recursive_flag = false;
173 luareader_fragment = NULL;
175 renderq_saved = NULL;
176 renderq_last = NULL;
177 renderq_redirect = false;
179 on_paint = new lua::state::callback_list(L, "paint", "on_paint");
180 on_video = new lua::state::callback_list(L, "video", "on_video");
181 on_reset = new lua::state::callback_list(L, "reset", "on_reset");
182 on_frame = new lua::state::callback_list(L, "frame", "on_frame");
183 on_rewind = new lua::state::callback_list(L, "rewind", "on_rewind");
184 on_idle = new lua::state::callback_list(L, "idle", "on_idle");
185 on_timer = new lua::state::callback_list(L, "timer", "on_timer");
186 on_frame_emulated = new lua::state::callback_list(L, "frame_emulated", "on_frame_emulated");
187 on_readwrite = new lua::state::callback_list(L, "readwrite", "on_readwrite");
188 on_startup = new lua::state::callback_list(L, "startup", "on_startup");
189 on_pre_load = new lua::state::callback_list(L, "pre_load", "on_pre_load");
190 on_post_load = new lua::state::callback_list(L, "post_load", "on_post_load");
191 on_err_load = new lua::state::callback_list(L, "err_load", "on_err_load");
192 on_pre_save = new lua::state::callback_list(L, "pre_save", "on_pre_save");
193 on_post_save = new lua::state::callback_list(L, "post_save", "on_post_save");
194 on_err_save = new lua::state::callback_list(L, "err_save", "on_err_save");
195 on_input = new lua::state::callback_list(L, "input", "on_input");
196 on_snoop = new lua::state::callback_list(L, "snoop", "on_snoop");
197 on_snoop2 = new lua::state::callback_list(L, "snoop2", "on_snoop2");
198 on_button = new lua::state::callback_list(L, "button", "on_button");
199 on_quit = new lua::state::callback_list(L, "quit", "on_quit");
200 on_keyhook = new lua::state::callback_list(L, "keyhook", "on_keyhook");
201 on_movie_lost = new lua::state::callback_list(L, "movie_lost", "on_movie_lost");
202 on_pre_rewind = new lua::state::callback_list(L, "pre_rewind", "on_pre_rewind");
203 on_post_rewind = new lua::state::callback_list(L, "post_rewind", "on_post_rewind");
204 on_set_rewind = new lua::state::callback_list(L, "set_rewind", "on_set_rewind");
205 on_latch = new lua::state::callback_list(L, "latch", "on_latch");
208 lua_state::~lua_state()
210 delete on_paint;
211 delete on_video;
212 delete on_reset;
213 delete on_frame;
214 delete on_rewind;
215 delete on_idle;
216 delete on_timer;
217 delete on_frame_emulated;
218 delete on_readwrite;
219 delete on_startup;
220 delete on_pre_load;
221 delete on_post_load;
222 delete on_err_load;
223 delete on_pre_save;
224 delete on_post_save;
225 delete on_err_save;
226 delete on_input;
227 delete on_snoop;
228 delete on_snoop2;
229 delete on_button;
230 delete on_quit;
231 delete on_keyhook;
232 delete on_movie_lost;
233 delete on_pre_rewind;
234 delete on_post_rewind;
235 delete on_set_rewind;
236 delete on_latch;
239 void lua_state::callback_do_paint(struct lua::render_context* ctx, bool non_synthetic) throw()
241 run_synchronous_paint(ctx);
242 run_callback(*on_paint, lua::state::store_tag(render_ctx, ctx), lua::state::boolean_tag(non_synthetic));
245 void lua_state::callback_do_video(struct lua::render_context* ctx, bool& _kill_frame, uint32_t& _hscl,
246 uint32_t& _vscl) throw()
248 run_callback(*on_video, lua::state::store_tag(render_ctx, ctx), lua::state::store_tag(kill_frame,
249 &_kill_frame), lua::state::store_tag(hscl, &_hscl), lua::state::store_tag(vscl, &_vscl));
252 void lua_state::callback_do_reset() throw()
254 run_callback(*on_reset);
257 void lua_state::callback_do_frame() throw()
259 run_callback(*on_frame);
262 void lua_state::callback_do_rewind() throw()
264 run_callback(*on_rewind);
267 void lua_state::callback_do_idle() throw()
269 idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
270 run_callback(*on_idle);
273 void lua_state::callback_do_timer() throw()
275 timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
276 run_callback(*on_timer);
279 void lua_state::callback_do_frame_emulated() throw()
281 run_callback(*on_frame_emulated);
284 void lua_state::callback_do_readwrite() throw()
286 run_callback(*on_readwrite);
289 void lua_state::callback_pre_load(const std::string& name) throw()
291 run_callback(*on_pre_load, lua::state::string_tag(name));
294 void lua_state::callback_err_load(const std::string& name) throw()
296 run_callback(*on_err_load, lua::state::string_tag(name));
299 void lua_state::callback_post_load(const std::string& name, bool was_state) throw()
301 run_callback(*on_post_load, lua::state::string_tag(name), lua::state::boolean_tag(was_state));
304 void lua_state::callback_pre_save(const std::string& name, bool is_state) throw()
306 run_callback(*on_pre_save, lua::state::string_tag(name), lua::state::boolean_tag(is_state));
309 void lua_state::callback_err_save(const std::string& name) throw()
311 run_callback(*on_err_save, lua::state::string_tag(name));
314 void lua_state::callback_post_save(const std::string& name, bool is_state) throw()
316 run_callback(*on_post_save, lua::state::string_tag(name), lua::state::boolean_tag(is_state));
319 void lua_state::callback_do_input(controller_frame& data, bool subframe) throw()
321 run_callback(*on_input, lua::state::store_tag(input_controllerdata, &data),
322 lua::state::boolean_tag(subframe));
325 void lua_state::callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
327 if(run_callback(*on_snoop2, lua::state::numeric_tag(port), lua::state::numeric_tag(controller),
328 lua::state::numeric_tag(index), lua::state::numeric_tag(value)))
329 return;
330 run_callback(*on_snoop, lua::state::numeric_tag(port), lua::state::numeric_tag(controller),
331 lua::state::numeric_tag(index), lua::state::numeric_tag(value));
334 bool lua_state::callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type)
336 bool flag = false;
337 run_callback(*on_button, lua::state::store_tag(veto_flag, &flag), lua::state::numeric_tag(port),
338 lua::state::numeric_tag(controller), lua::state::numeric_tag(index), lua::state::string_tag(type));
339 return flag;
342 namespace
344 command::fnptr<const std::string&> CMD_evaluate_lua(lsnes_cmds, "evaluate-lua", "Evaluate expression in "
345 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
346 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
347 if(args == "")
348 throw std::runtime_error("Expected expression to evaluate");
349 auto& core = CORE();
350 core.lua2->do_eval_lua(args);
353 command::fnptr<const std::string&> CMD_evaluate_lua2(lsnes_cmds, "L", "Evaluate expression in "
354 "Lua VM", "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
355 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
356 if(args == "")
357 throw std::runtime_error("Expected expression to evaluate");
358 auto& core = CORE();
359 core.lua2->do_eval_lua(args);
362 command::fnptr<command::arg_filename> CMD_run_lua(lsnes_cmds, "run-lua", "Run Lua script in Lua VM",
363 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
364 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error)
366 auto& core = CORE();
367 core.lua2->do_run_lua(args);
370 command::fnptr<> CMD_reset_lua(lsnes_cmds, "reset-lua", "Reset the Lua VM",
371 "Syntax: reset-lua\nReset the Lua VM.\n",
372 []() throw(std::bad_alloc, std::runtime_error)
374 auto& core = CORE();
375 core.lua->reset();
376 luaL_openlibs(core.lua->handle());
378 core.lua2->run_sysrc_lua(true);
379 copy_system_tables(*core.lua);
380 messages << "Lua VM reset" << std::endl;
383 lua::_class<lua_unsaferewind> LUA_class_unsaferewind(lua_class_movie, "UNSAFEREWIND", {}, {
384 }, &lua_unsaferewind::print);
387 void lua_state::callback_quit() throw()
389 run_callback(*on_quit);
392 void lua_state::callback_keyhook(const std::string& key, keyboard::key& p) throw()
394 run_callback(*on_keyhook, lua::state::string_tag(key), lua::state::fnptr_tag(push_keygroup_parameters2, &p));
397 void init_lua() throw()
399 auto& core = lsnes_instance;
400 core.lua->set_oom_handler(OOM_panic);
401 try {
402 core.lua->reset();
403 core.lua->add_function_group(lua_func_bit);
404 core.lua->add_function_group(lua_func_load);
405 core.lua->add_function_group(lua_func_misc);
406 core.lua->add_function_group(lua_func_zip);
407 core.lua->add_class_group(lua_class_callback);
408 core.lua->add_class_group(lua_class_gui);
409 core.lua->add_class_group(lua_class_bind);
410 core.lua->add_class_group(lua_class_pure);
411 core.lua->add_class_group(lua_class_movie);
412 core.lua->add_class_group(lua_class_memory);
413 core.lua->add_class_group(lua_class_fileio);
414 } catch(std::exception& e) {
415 messages << "Can't initialize Lua." << std::endl;
416 fatal_error();
418 luaL_openlibs(core.lua->handle());
419 core.lua2->run_sysrc_lua(false);
420 copy_system_tables(*core.lua);
423 void quit_lua() throw()
425 lsnes_instance.lua->deinit();
429 #define LUA_TIMED_HOOK_IDLE 0
430 #define LUA_TIMED_HOOK_TIMER 1
432 uint64_t lua_state::timed_hook(int timer) throw()
434 switch(timer) {
435 case LUA_TIMED_HOOK_IDLE:
436 return idle_hook_time;
437 case LUA_TIMED_HOOK_TIMER:
438 return timer_hook_time;
440 return 0;
443 void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov,
444 void* u)
446 auto& core = CORE();
447 if(u) {
448 lua_unsaferewind* u2 = reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u)->object();
449 //Load.
450 try {
451 run_callback(*on_pre_rewind);
452 run_callback(*on_movie_lost, "unsaferewind");
453 mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
454 mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
455 try { core.mlogic->get_mfile().host_memory = u2->hostmemory; } catch(...) {}
456 run_callback(*on_post_rewind);
457 delete reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u);
458 } catch(...) {
459 return;
461 } else {
462 //Save
463 run_callback(*on_set_rewind, lua::state::fn_tag([&core, save, secs, ssecs, &mov](lua::state& L) ->
464 int {
465 lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(*core.lua);
466 u2->state = save;
467 u2->secs = secs,
468 u2->ssecs = ssecs;
469 u2->hostmemory = core.mlogic->get_mfile().host_memory;
470 mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
471 return 1;
472 }));
476 void lua_state::callback_movie_lost(const char* what)
478 run_callback(*on_movie_lost, std::string(what));
481 void lua_state::callback_do_latch(std::list<std::string>& args)
483 run_callback(*on_latch, lua::state::vararg_tag(args));
486 lua_unsaferewind::lua_unsaferewind(lua::state& L)
490 void lua_state::run_startup_scripts()
492 for(auto i : startup_scripts) {
493 messages << "Trying to run Lua script: " << i << std::endl;
494 do_run_lua(i);
498 void lua_state::add_startup_script(const std::string& file)
500 startup_scripts.push_back(file);
503 const std::map<std::string, std::u32string>& lua_state::get_watch_vars()
505 return watch_vars;
508 bool lua_state::run_lua_fragment() throw(std::bad_alloc)
510 bool result = true;
511 if(recursive_flag)
512 return false;
513 #if LUA_VERSION_NUM == 501
514 int t = L.load(read_lua_fragment, &luareader_fragment, "run_lua_fragment");
515 #endif
516 #if LUA_VERSION_NUM == 502
517 int t = L.load(read_lua_fragment, &luareader_fragment, "run_lua_fragment", "t");
518 #endif
519 if(t == LUA_ERRSYNTAX) {
520 messages << "Can't run Lua: Internal syntax error: " << L.tostring(-1)
521 << std::endl;
522 L.pop(1);
523 return false;
525 if(t == LUA_ERRMEM) {
526 messages << "Can't run Lua: Out of memory" << std::endl;
527 L.pop(1);
528 return false;
530 recursive_flag = true;
531 int r = L.pcall(0, 0, 0);
532 recursive_flag = false;
533 if(r == LUA_ERRRUN) {
534 messages << "Error running Lua hunk: " << L.tostring(-1) << std::endl;
535 L.pop(1);
536 result = false;
538 if(r == LUA_ERRMEM) {
539 messages << "Error running Lua hunk: Out of memory" << std::endl;
540 L.pop(1);
541 result = false;
543 if(r == LUA_ERRERR) {
544 messages << "Error running Lua hunk: Double Fault???" << std::endl;
545 L.pop(1);
546 result = false;
548 render_ctx = NULL;
549 if(requests_repaint) {
550 requests_repaint = false;
551 command.invoke("repaint");
553 return result;
556 void lua_state::do_eval_lua(const std::string& c) throw(std::bad_alloc)
558 L.pushlstring(c.c_str(), c.length());
559 L.setglobal(TEMPORARY);
560 luareader_fragment = CONST_eval_lua_lua;
561 run_lua_fragment();
564 void lua_state::do_run_lua(const std::string& c) throw(std::bad_alloc)
566 L.pushlstring(c.c_str(), c.length());
567 L.setglobal(TEMPORARY);
568 luareader_fragment = CONST_run_lua_lua;
569 run_lua_fragment();
572 template<typename... T> bool lua_state::run_callback(lua::state::callback_list& list, T... args)
574 if(recursive_flag)
575 return true;
576 recursive_flag = true;
577 try {
578 if(!list.callback(args...)) {
579 recursive_flag = false;
580 return false;
582 } catch(std::exception& e) {
583 messages << e.what() << std::endl;
585 recursive_flag = false;
586 render_ctx = NULL;
587 if(requests_repaint) {
588 requests_repaint = false;
589 command.invoke("repaint");
591 return true;
594 void lua_state::run_sysrc_lua(bool rerun)
596 L.pushstring(lua_sysrc_script);
597 L.setglobal(TEMPORARY);
598 luareader_fragment = CONST_eval_sysrc_lua;
599 if(!run_lua_fragment() && !rerun) {
600 //run_lua_fragment shows error.
601 //messages << "Failed to run sysrc lua script" << std::endl;
602 fatal_error();
606 void lua_state::run_synchronous_paint(struct lua::render_context* ctx)
608 if(!synchronous_paint_ctx)
609 return;
610 lua_renderq_run(ctx, synchronous_paint_ctx);