1 #include "core/lua.hpp"
4 struct lua_State
{ int x
; };
5 lua_function::lua_function(const std::string
& name
) throw(std::bad_alloc
) {}
6 lua_function::~lua_function() throw() {}
7 void lua_callback_do_paint(struct lua_render_context
* ctx
) throw() {}
8 void lua_callback_do_video(struct lua_render_context
* ctx
) throw() {}
9 void lua_callback_do_input(controls_t
& data
, bool subframe
) throw() {}
10 void lua_callback_do_reset() throw() {}
11 void lua_callback_do_frame() throw() {}
12 void lua_callback_do_readwrite() throw() {}
13 void lua_callback_startup() throw() {}
14 void lua_callback_pre_load(const std::string
& name
) throw() {}
15 void lua_callback_err_load(const std::string
& name
) throw() {}
16 void lua_callback_post_load(const std::string
& name
, bool was_state
) throw() {}
17 void lua_callback_pre_save(const std::string
& name
, bool is_state
) throw() {}
18 void lua_callback_err_save(const std::string
& name
) throw() {}
19 void lua_callback_post_save(const std::string
& name
, bool is_state
) throw() {}
20 void lua_callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw() {}
21 void lua_callback_quit() throw() {}
22 void init_lua() throw() {}
23 bool lua_requests_repaint
= false;
24 bool lua_requests_subframe_paint
= false;
25 bool lua_supported
= false;
28 #include "core/command.hpp"
29 #include "core/globalwrap.hpp"
30 #include "core/lua-int.hpp"
31 #include "core/mainloop.hpp"
32 #include "core/memorymanip.hpp"
33 #include "core/misc.hpp"
46 globalwrap
<std::map
<std::string
, lua_function
*>> functions
;
47 lua_State
* lua_initialized
;
48 int lua_trampoline_function(lua_State
* L
)
50 void* ptr
= lua_touserdata(L
, lua_upvalueindex(1));
51 lua_function
* f
= reinterpret_cast<lua_function
*>(ptr
);
55 //Pushes given table to top of stack, creating if needed.
56 void recursive_lookup_table(lua_State
* L
, const std::string
& tab
)
59 lua_pushvalue(L
, LUA_GLOBALSINDEX
);
63 size_t split
= u
.find_last_of(".");
66 if(split
< u
.length()) {
67 u1
= u
.substr(0, split
);
68 u2
= u
.substr(split
+ 1);
70 recursive_lookup_table(L
, u1
);
71 lua_getfield(L
, -1, u2
.c_str());
72 if(lua_type(L
, -1) != LUA_TTABLE
) {
73 //Not a table, create a table.
76 lua_setfield(L
, -2, u2
.c_str());
77 lua_getfield(L
, -1, u2
.c_str());
79 //Get rid of previous table.
84 void register_lua_function(lua_State
* L
, const std::string
& fun
)
87 size_t split
= u
.find_last_of(".");
90 if(split
< u
.length()) {
91 u1
= u
.substr(0, split
);
92 u2
= u
.substr(split
+ 1);
94 recursive_lookup_table(L
, u1
);
95 void* ptr
= reinterpret_cast<void*>(functions()[fun
]);
96 lua_pushlightuserdata(L
, ptr
);
97 lua_pushcclosure(L
, lua_trampoline_function
, 1);
98 lua_setfield(L
, -2, u2
.c_str());
102 void register_lua_functions(lua_State
* L
)
104 for(auto i
: functions())
105 register_lua_function(L
, i
.first
);
110 lua_function::lua_function(const std::string
& name
) throw(std::bad_alloc
)
112 functions()[fname
= name
] = this;
114 register_lua_function(lua_initialized
, fname
);
117 lua_function::~lua_function() throw()
119 functions().erase(fname
);
122 std::string
get_string_argument(lua_State
* LS
, unsigned argindex
, const char* fname
)
124 if(lua_isnone(LS
, argindex
)) {
126 sprintf(buffer
, "argument #%i to %s must be string", argindex
, fname
);
127 lua_pushstring(LS
, buffer
);
131 const char* f
= lua_tolstring(LS
, argindex
, &len
);
134 sprintf(buffer
, "argument #%i to %s must be string", argindex
, fname
);
135 lua_pushstring(LS
, buffer
);
138 return std::string(f
, f
+ len
);
141 bool get_boolean_argument(lua_State
* LS
, unsigned argindex
, const char* fname
)
143 if(lua_isnone(LS
, argindex
) || !lua_isboolean(LS
, argindex
)) {
145 sprintf(buffer
, "argument #%i to %s must be boolean", argindex
, fname
);
146 lua_pushstring(LS
, buffer
);
149 return (lua_toboolean(LS
, argindex
) != 0);
152 lua_render_context
* lua_render_ctx
= NULL
;
153 controls_t
* lua_input_controllerdata
= NULL
;
158 bool recursive_flag
= false;
159 const char* luareader_fragment
= NULL
;
161 const char* read_lua_fragment(lua_State
* LS
, void* dummy
, size_t* size
)
163 if(luareader_fragment
) {
164 const char* ret
= luareader_fragment
;
165 *size
= strlen(luareader_fragment
);
166 luareader_fragment
= NULL
;
174 void* alloc(void* user
, void* old
, size_t olds
, size_t news
)
177 void* m
= realloc(old
, news
);
186 bool callback_exists(const char* name
)
190 lua_getglobal(L
, name
);
191 int t
= lua_type(L
, -1);
192 if(t
!= LUA_TFUNCTION
)
194 return (t
== LUA_TFUNCTION
);
197 void push_string(const std::string
& s
)
199 lua_pushlstring(L
, s
.c_str(), s
.length());
202 void push_boolean(bool b
)
204 lua_pushboolean(L
, b
? 1 : 0);
207 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
209 const char* eval_lua_lua
= "loadstring(" TEMPORARY
")();";
210 const char* run_lua_lua
= "dofile(" TEMPORARY
");";
212 void run_lua_fragment() throw(std::bad_alloc
)
216 int t
= lua_load(L
, read_lua_fragment
, NULL
, "run_lua_fragment");
217 if(t
== LUA_ERRSYNTAX
) {
218 messages
<< "Can't run Lua: Internal syntax error: " << lua_tostring(L
, -1) << std::endl
;
222 if(t
== LUA_ERRMEM
) {
223 messages
<< "Can't run Lua: Out of memory" << std::endl
;
227 recursive_flag
= true;
228 int r
= lua_pcall(L
, 0, 0, 0);
229 recursive_flag
= false;
230 if(r
== LUA_ERRRUN
) {
231 messages
<< "Error running Lua hunk: " << lua_tostring(L
, -1) << std::endl
;
234 if(r
== LUA_ERRMEM
) {
235 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
238 if(r
== LUA_ERRERR
) {
239 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
242 if(lua_requests_repaint
) {
243 lua_requests_repaint
= false;
244 command::invokeC("repaint");
248 void do_eval_lua(const std::string
& c
) throw(std::bad_alloc
)
251 lua_setglobal(L
, TEMPORARY
);
252 luareader_fragment
= eval_lua_lua
;
256 void do_run_lua(const std::string
& c
) throw(std::bad_alloc
)
259 lua_setglobal(L
, TEMPORARY
);
260 luareader_fragment
= run_lua_lua
;
264 void run_lua_cb(int args
) throw()
266 recursive_flag
= true;
267 int r
= lua_pcall(L
, args
, 0, 0);
268 recursive_flag
= false;
269 if(r
== LUA_ERRRUN
) {
270 messages
<< "Error running Lua callback: " << lua_tostring(L
, -1) << std::endl
;
273 if(r
== LUA_ERRMEM
) {
274 messages
<< "Error running Lua callback: Out of memory" << std::endl
;
277 if(r
== LUA_ERRERR
) {
278 messages
<< "Error running Lua callback: Double Fault???" << std::endl
;
281 if(lua_requests_repaint
) {
282 lua_requests_repaint
= false;
283 command::invokeC("repaint");
287 int system_write_error(lua_State
* L
)
289 lua_pushstring(L
, "_SYSTEM is write-protected");
294 void copy_system_tables(lua_State
* L
)
298 while(lua_next(L
, LUA_GLOBALSINDEX
)) {
299 //Stack: _SYSTEM, KEY, VALUE
300 lua_pushvalue(L
, -2);
301 lua_pushvalue(L
, -2);
302 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
304 //Stack: _SYSTEM, KEY, VALUE
306 //Stack: _SYSTEM, KEY
309 lua_pushcfunction(L
, system_write_error
);
310 lua_setfield(L
, -2, "__newindex");
311 lua_setmetatable(L
, -2);
312 lua_setglobal(L
, "_SYSTEM");
316 void lua_callback_do_paint(struct lua_render_context
* ctx
) throw()
318 if(!callback_exists("on_paint"))
320 lua_render_ctx
= ctx
;
322 lua_render_ctx
= NULL
;
325 void lua_callback_do_video(struct lua_render_context
* ctx
) throw()
327 if(!callback_exists("on_video"))
329 lua_render_ctx
= ctx
;
331 lua_render_ctx
= NULL
;
334 void lua_callback_do_reset() throw()
336 if(!callback_exists("on_reset"))
341 void lua_callback_do_frame() throw()
343 if(!callback_exists("on_frame"))
348 void lua_callback_do_readwrite() throw()
350 if(!callback_exists("on_readwrite"))
355 void lua_callback_startup() throw()
357 if(!callback_exists("on_startup"))
362 void lua_callback_pre_load(const std::string
& name
) throw()
364 if(!callback_exists("on_pre_load"))
370 void lua_callback_err_load(const std::string
& name
) throw()
372 if(!callback_exists("on_err_load"))
378 void lua_callback_post_load(const std::string
& name
, bool was_state
) throw()
380 if(!callback_exists("on_post_load"))
383 push_boolean(was_state
);
387 void lua_callback_pre_save(const std::string
& name
, bool is_state
) throw()
389 if(!callback_exists("on_pre_save"))
392 push_boolean(is_state
);
396 void lua_callback_err_save(const std::string
& name
) throw()
398 if(!callback_exists("on_err_save"))
404 void lua_callback_post_save(const std::string
& name
, bool is_state
) throw()
406 if(!callback_exists("on_post_save"))
409 push_boolean(is_state
);
413 void lua_callback_do_input(controls_t
& data
, bool subframe
) throw()
415 if(!callback_exists("on_input"))
417 lua_input_controllerdata
= &data
;
418 push_boolean(subframe
);
420 lua_input_controllerdata
= NULL
;
423 void lua_callback_snoop_input(uint32_t port
, uint32_t controller
, uint32_t index
, short value
) throw()
425 if(!callback_exists("on_snoop"))
427 lua_pushnumber(L
, port
);
428 lua_pushnumber(L
, controller
);
429 lua_pushnumber(L
, index
);
430 lua_pushnumber(L
, value
);
436 function_ptr_command
<const std::string
&> evaluate_lua("evaluate-lua", "Evaluate expression in Lua VM",
437 "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
438 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
440 throw std::runtime_error("Expected expression to evaluate");
444 function_ptr_command
<arg_filename
> run_lua("run-lua", "Run Lua script in Lua VM",
445 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
446 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
)
452 void lua_callback_quit() throw()
454 if(!callback_exists("on_quit"))
459 void init_lua() throw()
461 L
= lua_newstate(alloc
, NULL
);
463 messages
<< "Can't initialize Lua." << std::endl
;
468 register_lua_functions(L
);
469 copy_system_tables(L
);
472 bool lua_requests_repaint
= false;
473 bool lua_requests_subframe_paint
= false;
474 bool lua_supported
= true;