1 #include "lua-base.hpp"
2 #include "lua-class.hpp"
3 #include "lua-function.hpp"
4 #include "lua-params.hpp"
6 #include "register-queue.hpp"
12 std::unordered_map
<std::type_index
, void*>& class_types()
14 static std::unordered_map
<std::type_index
, void*> x
;
20 char classtable_meta_key
;
25 static int index(lua_State
* L
);
26 static int newindex(lua_State
* L
);
27 static int pairs(lua_State
* L
);
28 static int pairs_next(lua_State
* L
);
29 static int smethods(lua_State
* L
);
30 static int cmethods(lua_State
* L
);
31 static int trampoline(lua_State
* L
);
32 static void check(lua_State
* L
);
35 void class_info::check(lua_State
* L
)
37 lua_pushlightuserdata(L
, &classtable_meta_key
);
38 lua_rawget(L
, LUA_REGISTRYINDEX
);
39 lua_getmetatable(L
, 1);
40 if(!lua_rawequal(L
, -1, -2)) {
41 lua_pushstring(L
, "Bad class table");
47 int class_info::index(lua_State
* L
)
51 class_base
* ptr
= ((class_info
*)lua_touserdata(L
, 1))->obj
;
52 const char* method
= lua_tostring(L
, 2);
54 lua_pushstring(L
, "Indexing invalid element of class table");
57 if(!strcmp(method
, "_static_methods")) {
58 lua_pushlightuserdata(L
, ptr
);
59 lua_pushcclosure(L
, class_info::smethods
, 1);
61 } else if(!strcmp(method
, "_class_methods")) {
62 lua_pushlightuserdata(L
, ptr
);
63 lua_pushcclosure(L
, class_info::cmethods
, 1);
66 auto m
= ptr
->static_methods();
68 if(!strcmp(i
.name
, method
)) {
70 std::string name
= ptr
->get_name() + "::" + method
;
71 lua_pushvalue(L
, lua_upvalueindex(1)); //State.
72 lua_pushlightuserdata(L
, (void*)i
.fn
);
73 std::string fname
= ptr
->get_name() + "::" + i
.name
;
74 lua_pushstring(L
, fname
.c_str());
75 lua_pushcclosure(L
, class_info::trampoline
, 3);
79 std::string err
= std::string("Class '") + ptr
->get_name() +
80 "' does not have static method '" + method
+ "'";
81 lua_pushstring(L
, err
.c_str());
85 int class_info::newindex(lua_State
* L
)
87 lua_pushstring(L
, "Writing into class table not allowed");
91 int class_info::pairs(lua_State
* _xL
)
95 lua::state
* _L
= (lua::state
*)lua_touserdata(_xL
, lua_upvalueindex(1));
97 class_base
* obj
= ((class_info
*)L
.touserdata(1))->obj
;
99 L
.pushvalue(lua_upvalueindex(1));
100 L
.pushcclosure(class_info::pairs_next
, 1); //Next
101 L
.pushvalue(1); //State.
102 L
.pushnil(); //Index.
106 int class_info::pairs_next(lua_State
* _xL
)
110 lua::state
* _L
= (lua::state
*)lua_touserdata(_xL
, lua_upvalueindex(1));
112 class_base
* obj
= ((class_info
*)L
.touserdata(1))->obj
;
113 auto m
= obj
->static_methods();
114 std::string key
= (L
.type(2) == LUA_TSTRING
) ? L
.tostring(2) : "";
115 std::string lowbound
= "\xFF"; //Sorts greater than anything that is valid UTF-8.
116 void* best_fn
= NULL
;
118 if(lowbound
> i
.name
&& i
.name
> key
) {
120 best_fn
= (void*)i
.fn
;
123 L
.pushlstring(lowbound
);
124 std::string name
= obj
->get_name() + "::" + lowbound
;
125 L
.pushvalue(lua_upvalueindex(1)); //State.
126 L
.pushlightuserdata(best_fn
);
128 L
.pushcclosure(class_info::trampoline
, 3);
136 int class_info::smethods(lua_State
* L
)
138 class_base
* obj
= (class_base
*)lua_touserdata(L
, lua_upvalueindex(1));
139 auto m
= obj
->static_methods();
142 lua_pushstring(L
, i
.name
);
148 int class_info::cmethods(lua_State
* L
)
150 class_base
* obj
= (class_base
*)lua_touserdata(L
, lua_upvalueindex(1));
151 auto m
= obj
->class_methods();
154 lua_pushstring(L
, i
.c_str());
160 typedef int (*fn_t
)(state
& L
, parameters
& P
);
162 int class_info::trampoline(lua_State
* L
)
164 state
* lstate
= reinterpret_cast<state
*>(lua_touserdata(L
, lua_upvalueindex(1)));
165 void* _fn
= lua_touserdata(L
, lua_upvalueindex(2));
167 std::string name
= lua_tostring(L
, lua_upvalueindex(3));
168 state
_L(*lstate
, L
);
170 parameters
P(_L
, name
);
172 } catch(std::exception
& e
) {
173 lua_pushfstring(L
, "%s", e
.what());
179 int lua_trampoline_function(lua_State
* L
)
181 void* ptr
= lua_touserdata(L
, lua_upvalueindex(1));
182 state
* lstate
= reinterpret_cast<state
*>(lua_touserdata(L
, lua_upvalueindex(2)));
183 function
* f
= reinterpret_cast<function
*>(ptr
);
184 state
_L(*lstate
, L
);
186 return f
->invoke(_L
);
187 } catch(std::exception
& e
) {
188 lua_pushfstring(L
, "%s", e
.what());
194 //Pushes given table to top of stack, creating if needed.
195 void recursive_lookup_table(state
& L
, const std::string
& tab
)
198 #if LUA_VERSION_NUM == 501
199 L
.pushvalue(LUA_GLOBALSINDEX
);
201 #if LUA_VERSION_NUM == 502
202 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
204 assert(L
.type(-1) == LUA_TTABLE
);
208 size_t split
= u
.find_last_of(".");
211 if(split
< u
.length()) {
212 u1
= u
.substr(0, split
);
213 u2
= u
.substr(split
+ 1);
215 recursive_lookup_table(L
, u1
);
216 L
.getfield(-1, u2
.c_str());
217 if(L
.type(-1) != LUA_TTABLE
) {
218 //Not a table, create a table.
221 L
.setfield(-2, u2
.c_str());
222 L
.getfield(-1, u2
.c_str());
224 //Get rid of previous table.
229 void register_function(state
& L
, const std::string
& name
, function
* fun
)
231 std::string u
= name
;
232 size_t split
= u
.find_last_of(".");
235 if(split
< u
.length()) {
236 u1
= u
.substr(0, split
);
237 u2
= u
.substr(split
+ 1);
239 recursive_lookup_table(L
, u1
);
243 void* ptr
= reinterpret_cast<void*>(fun
);
244 L
.pushlightuserdata(ptr
);
245 L
.pushlightuserdata(&L
);
246 L
.pushcclosure(lua_trampoline_function
, 2);
248 L
.setfield(-2, u2
.c_str());
252 void register_class(state
& L
, const std::string
& name
, class_base
* fun
)
254 fun
->register_state(L
);
257 typedef register_queue
<state
, function
> regqueue_t
;
258 typedef register_queue
<state::callback_proxy
, state::callback_list
> regqueue2_t
;
259 typedef register_queue
<function_group
, function
> regqueue3_t
;
260 typedef register_queue
<class_group
, class_base
> regqueue4_t
;
263 state::state() throw(std::bad_alloc
)
268 oom_handler
= builtin_oom
;
269 regqueue2_t::do_ready(cbproxy
, true);
272 state::state(state
& _master
, lua_State
* L
)
279 state::~state() throw()
283 for(auto i
: function_groups
)
284 i
.first
->drop_callback(i
.second
);
285 for(auto i
: class_groups
)
286 i
.first
->drop_callback(i
.second
);
287 regqueue2_t::do_ready(cbproxy
, false);
289 lua_close(lua_handle
);
292 void state::builtin_oom()
294 std::cerr
<< "PANIC: FATAL: Out of memory" << std::endl
;
298 void* state::builtin_alloc(void* user
, void* old
, size_t olds
, size_t news
)
301 void* m
= realloc(old
, news
);
303 reinterpret_cast<state
*>(user
)->oom_handler();
311 function::function(function_group
& _group
, const std::string
& func
) throw(std::bad_alloc
)
314 regqueue3_t::do_register(group
, fname
= func
, *this);
317 function::~function() throw()
319 regqueue3_t::do_unregister(group
, fname
);
322 class_base::class_base(class_group
& _group
, const std::string
& _name
)
323 : group(_group
), name(_name
)
328 class_base::~class_base() throw()
331 regqueue4_t::do_unregister(group
, name
);
334 void state::reset() throw(std::bad_alloc
, std::runtime_error
)
337 return master
->reset();
339 lua_State
* tmp
= lua_newstate(state::builtin_alloc
, this);
341 throw std::runtime_error("Can't re-initialize Lua interpretter");
342 lua_close(lua_handle
);
343 for(auto& i
: callbacks
)
348 lua_handle
= lua_newstate(state::builtin_alloc
, this);
350 throw std::runtime_error("Can't initialize Lua interpretter");
352 for(auto i
: function_groups
)
353 i
.first
->request_callback([this](std::string name
, function
* func
) -> void {
354 register_function(*this, name
, func
);
356 for(auto i
: class_groups
)
357 i
.first
->request_callback([this](std::string name
, class_base
* clazz
) -> void {
358 register_class(*this, name
, clazz
);
362 void state::deinit() throw()
365 return master
->deinit();
367 lua_close(lua_handle
);
371 void state::add_function_group(function_group
& group
)
373 function_groups
.insert(std::make_pair(&group
, group
.add_callback([this](const std::string
& name
,
374 function
* func
) -> void {
375 this->function_callback(name
, func
);
376 }, [this](function_group
* x
) {
377 for(auto i
= this->function_groups
.begin(); i
!= this->function_groups
.end();)
379 i
= this->function_groups
.erase(i
);
385 void state::add_class_group(class_group
& group
)
387 class_groups
.insert(std::make_pair(&group
, group
.add_callback([this](const std::string
& name
,
388 class_base
* clazz
) -> void {
389 this->class_callback(name
, clazz
);
390 }, [this](class_group
* x
) {
391 for(auto i
= this->class_groups
.begin(); i
!= this->class_groups
.end();)
393 i
= this->class_groups
.erase(i
);
399 void state::function_callback(const std::string
& name
, function
* func
)
402 return master
->function_callback(name
, func
);
404 register_function(*this, name
, func
);
407 void state::class_callback(const std::string
& name
, class_base
* clazz
)
410 return master
->class_callback(name
, clazz
);
412 register_class(*this, name
, clazz
);
415 bool state::do_once(void* key
)
418 return master
->do_once(key
);
419 pushlightuserdata(key
);
420 rawget(LUA_REGISTRYINDEX
);
421 if(type(-1) == LUA_TNIL
) {
423 pushlightuserdata(key
);
424 pushlightuserdata(key
);
425 rawset(LUA_REGISTRYINDEX
);
433 state::callback_list::callback_list(state
& _L
, const std::string
& _name
, const std::string
& fncbname
)
434 : L(_L
), name(_name
), fn_cbname(fncbname
)
436 regqueue2_t::do_register(L
.cbproxy
, name
, *this);
439 state::callback_list::~callback_list()
441 regqueue2_t::do_unregister(L
.cbproxy
, name
);
444 for(auto& i
: callbacks
) {
445 L
.pushlightuserdata(&i
);
447 L
.rawset(LUA_REGISTRYINDEX
);
451 void state::callback_list::_register(state
& _L
)
453 callbacks
.push_back(0);
454 _L
.pushlightuserdata(&*callbacks
.rbegin());
456 _L
.rawset(LUA_REGISTRYINDEX
);
459 void state::callback_list::_unregister(state
& _L
)
461 for(auto i
= callbacks
.begin(); i
!= callbacks
.end();) {
462 _L
.pushlightuserdata(&*i
);
463 _L
.rawget(LUA_REGISTRYINDEX
);
464 if(_L
.rawequal(-1, -2)) {
466 _L
.pushlightuserdata(key
);
468 _L
.rawset(LUA_REGISTRYINDEX
);
469 i
= callbacks
.erase(i
);
476 function_group::function_group()
479 regqueue3_t::do_ready(*this, true);
482 function_group::~function_group()
484 for(auto i
: functions
)
485 for(auto j
: callbacks
)
486 j
.second(i
.first
, NULL
);
487 for(auto i
: dcallbacks
)
489 regqueue3_t::do_ready(*this, false);
492 void function_group::request_callback(std::function
<void(std::string
, function
*)> cb
)
494 for(auto i
: functions
)
495 cb(i
.first
, i
.second
);
498 int function_group::add_callback(std::function
<void(std::string
, function
*)> cb
,
499 std::function
<void(function_group
*)> dcb
)
501 int handle
= next_handle
++;
502 callbacks
[handle
] = cb
;
503 dcallbacks
[handle
] = dcb
;
504 for(auto i
: functions
)
505 cb(i
.first
, i
.second
);
509 void function_group::drop_callback(int handle
)
511 callbacks
.erase(handle
);
514 void function_group::do_register(const std::string
& name
, function
& fun
)
516 functions
[name
] = &fun
;
517 for(auto i
: callbacks
)
518 i
.second(name
, &fun
);
521 void function_group::do_unregister(const std::string
& name
)
523 functions
.erase(name
);
524 for(auto i
: callbacks
)
525 i
.second(name
, NULL
);
528 class_group::class_group()
531 regqueue4_t::do_ready(*this, true);
534 class_group::~class_group()
536 for(auto i
: classes
)
537 for(auto j
: callbacks
)
538 j
.second(i
.first
, NULL
);
539 for(auto i
: dcallbacks
)
541 regqueue4_t::do_ready(*this, false);
544 void class_group::request_callback(std::function
<void(std::string
, class_base
*)> cb
)
546 for(auto i
: classes
)
547 cb(i
.first
, i
.second
);
550 int class_group::add_callback(std::function
<void(std::string
, class_base
*)> cb
,
551 std::function
<void(class_group
*)> dcb
)
553 int handle
= next_handle
++;
554 callbacks
[handle
] = cb
;
555 dcallbacks
[handle
] = dcb
;
556 for(auto i
: classes
)
557 cb(i
.first
, i
.second
);
561 void class_group::drop_callback(int handle
)
563 callbacks
.erase(handle
);
566 void class_group::do_register(const std::string
& name
, class_base
& fun
)
568 classes
[name
] = &fun
;
569 for(auto i
: callbacks
)
570 i
.second(name
, &fun
);
573 void class_group::do_unregister(const std::string
& name
)
576 for(auto i
: callbacks
)
577 i
.second(name
, NULL
);
580 std::list
<class_ops
>& userdata_recogn_fns()
582 static std::list
<class_ops
> x
;
586 std::string
try_recognize_userdata(state
& state
, int index
)
588 for(auto i
: userdata_recogn_fns())
589 if(i
.is(state
, index
))
591 //Hack: Lua builtin file objects and classobjs.
592 if(state
.getmetatable(index
)) {
593 state
.pushstring("FILE*");
594 state
.rawget(LUA_REGISTRYINDEX
);
595 if(state
.rawequal(-1, -2)) {
600 state
.pushlightuserdata(&classtable_meta_key
);
601 state
.rawget(LUA_REGISTRYINDEX
);
602 if(state
.rawequal(-1, -2)) {
611 std::string
try_print_userdata(state
& L
, int index
)
613 for(auto i
: userdata_recogn_fns())
615 return i
.print(L
, index
);
617 if(L
.getmetatable(index
)) {
618 L
.pushlightuserdata(&classtable_meta_key
);
619 L
.rawget(LUA_REGISTRYINDEX
);
620 if(L
.rawequal(-1, -2)) {
622 std::string cname
= ((class_info
*)L
.touserdata(index
))->obj
->get_name();
627 return "no data available";
630 int state::vararg_tag::pushargs(state
& L
)
638 else if(i
== "false")
639 L
.pushboolean(false);
640 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i
))
641 L
.pushnumber(strtod(i
.c_str(), NULL
));
643 L
.pushlstring(i
.substr(1));
651 class_base
* class_base::lookup(state
& L
, const std::string
& _name
)
653 if(lookup_and_push(L
, _name
)) {
654 class_base
* obj
= ((class_info
*)L
.touserdata(-1))->obj
;
661 bool class_base::lookup_and_push(state
& L
, const std::string
& _name
)
663 L
.pushlightuserdata(&classtable_key
);
664 L
.rawget(LUA_REGISTRYINDEX
);
665 if(L
.type(-1) == LUA_TNIL
) {
670 //On top of stack there is class table.
671 L
.pushlstring(_name
);
673 if(L
.type(-1) == LUA_TNIL
) {
683 std::set
<std::string
> class_base::all_classes(state
& L
)
685 L
.pushlightuserdata(&classtable_key
);
686 L
.rawget(LUA_REGISTRYINDEX
);
687 if(L
.type(-1) == LUA_TNIL
) {
690 return std::set
<std::string
>();
692 std::set
<std::string
> r
;
695 L
.pop(1); //Pop value.
696 if(L
.type(-1) == LUA_TSTRING
) r
.insert(L
.tostring(-1));
702 void class_base::register_static(state
& L
)
705 L
.pushlightuserdata(&classtable_key
);
706 L
.rawget(LUA_REGISTRYINDEX
);
707 if(L
.type(-1) == LUA_TNIL
) {
709 L
.pushlightuserdata(&classtable_key
);
711 L
.rawset(LUA_REGISTRYINDEX
);
714 //On top of stack there is class table.
717 if(L
.type(-1) != LUA_TNIL
) {
718 //Already registered.
724 //Now construct the object.
725 class_info
* ci
= (class_info
*)L
.newuserdata(sizeof(class_info
));
728 L
.pushlightuserdata(&classtable_meta_key
);
729 L
.rawget(LUA_REGISTRYINDEX
);
730 if(L
.type(-1) == LUA_TNIL
) {
732 L
.pushlightuserdata(&classtable_meta_key
);
734 L
.pushstring("__index");
735 L
.pushlightuserdata(&L
);
736 L
.pushcclosure(class_info::index
, 1);
738 L
.pushstring("__newindex");
739 L
.pushcfunction(class_info::newindex
);
741 L
.pushstring("__pairs");
742 L
.pushlightuserdata(&L
);
743 L
.pushcclosure(class_info::pairs
, 1);
745 L
.rawset(LUA_REGISTRYINDEX
);
753 void class_base::delayed_register()
755 regqueue4_t::do_register(group
, name
, *this);
758 functions::functions(function_group
& grp
, const std::string
& basetable
, std::initializer_list
<entry
> fnlist
)
760 std::string base
= (basetable
== "") ? "" : (basetable
+ ".");
762 funcs
.insert(new fn(grp
, base
+ i
.name
, i
.func
));
765 functions::~functions()
771 functions::fn::fn(function_group
& grp
, const std::string
& name
, std::function
<int(state
& L
, parameters
& P
)> _func
)
772 : function(grp
, name
)
777 functions::fn::~fn() throw()
781 int functions::fn::invoke(state
& L
)
783 lua::parameters
P(L
, fname
);