1 #include "lua-base.hpp"
2 #include "lua-class.hpp"
3 #include "lua-function.hpp"
4 #include "lua-params.hpp"
6 #include "stateobject.hpp"
15 threads::rlock
* global_lock
;
16 threads::rlock
& get_lua_lock()
18 if(!global_lock
) global_lock
= new threads::rlock
;
24 std::map
<std::string
, state::callback_list
*> callbacks
;
25 std::set
<std::pair
<function_group
*, int>> function_groups
;
26 std::set
<std::pair
<class_group
*, int>> class_groups
;
29 struct fgroup_internal
35 std::map
<std::string
, function
*> functions
;
37 std::map
<int, std::function
<void(std::string
, function
*)>> callbacks
;
38 std::map
<int, std::function
<void(function_group
*)>> dcallbacks
;
41 struct cgroup_internal
48 std::map
<std::string
, class_base
*> classes
;
49 std::map
<int, std::function
<void(std::string
, class_base
*)>> callbacks
;
50 std::map
<int, std::function
<void(class_group
*)>> dcallbacks
;
53 typedef stateobject::type
<state
, state_internal
> state_internal_t
;
54 typedef stateobject::type
<function_group
, fgroup_internal
> fgroup_internal_t
;
55 typedef stateobject::type
<class_group
, cgroup_internal
> cgroup_internal_t
;
58 std::unordered_map
<std::type_index
, void*>& class_types()
60 static std::unordered_map
<std::type_index
, void*> x
;
66 char classtable_meta_key
;
71 static int index(lua_State
* L
);
72 static int newindex(lua_State
* L
);
73 static int pairs(lua_State
* L
);
74 static int pairs_next(lua_State
* L
);
75 static int smethods(lua_State
* L
);
76 static int cmethods(lua_State
* L
);
77 static int trampoline(lua_State
* L
);
78 static void check(lua_State
* L
);
81 void class_info::check(lua_State
* L
)
83 lua_pushlightuserdata(L
, &classtable_meta_key
);
84 lua_rawget(L
, LUA_REGISTRYINDEX
);
85 lua_getmetatable(L
, 1);
86 if(!lua_rawequal(L
, -1, -2)) {
87 lua_pushstring(L
, "Bad class table");
93 int class_info::index(lua_State
* L
)
97 class_base
* ptr
= ((class_info
*)lua_touserdata(L
, 1))->obj
;
98 const char* method
= lua_tostring(L
, 2);
100 lua_pushstring(L
, "Indexing invalid element of class table");
103 if(!strcmp(method
, "_static_methods")) {
104 lua_pushlightuserdata(L
, ptr
);
105 lua_pushcclosure(L
, class_info::smethods
, 1);
107 } else if(!strcmp(method
, "_class_methods")) {
108 lua_pushlightuserdata(L
, ptr
);
109 lua_pushcclosure(L
, class_info::cmethods
, 1);
112 auto m
= ptr
->static_methods();
114 if(!strcmp(i
.name
, method
)) {
116 std::string name
= ptr
->get_name() + "::" + method
;
117 lua_pushvalue(L
, lua_upvalueindex(1)); //State.
118 lua_pushlightuserdata(L
, (void*)i
.fn
);
119 std::string fname
= ptr
->get_name() + "::" + i
.name
;
120 lua_pushstring(L
, fname
.c_str());
121 lua_pushcclosure(L
, class_info::trampoline
, 3);
125 std::string err
= std::string("Class '") + ptr
->get_name() +
126 "' does not have static method '" + method
+ "'";
127 lua_pushstring(L
, err
.c_str());
130 return 0; //NOTREACHED
132 int class_info::newindex(lua_State
* L
)
134 lua_pushstring(L
, "Writing into class table not allowed");
136 return 0; //NOTREACHED
139 int class_info::pairs(lua_State
* _xL
)
143 lua::state
* _L
= (lua::state
*)lua_touserdata(_xL
, lua_upvalueindex(1));
146 L
.pushvalue(lua_upvalueindex(1));
147 L
.pushcclosure(class_info::pairs_next
, 1); //Next
148 L
.pushvalue(1); //State.
149 L
.pushnil(); //Index.
153 int class_info::pairs_next(lua_State
* _xL
)
157 lua::state
* _L
= (lua::state
*)lua_touserdata(_xL
, lua_upvalueindex(1));
159 class_base
* obj
= ((class_info
*)L
.touserdata(1))->obj
;
160 auto m
= obj
->static_methods();
161 std::string key
= (L
.type(2) == LUA_TSTRING
) ? L
.tostring(2) : "";
162 std::string lowbound
= "\xFF"; //Sorts greater than anything that is valid UTF-8.
163 void* best_fn
= NULL
;
165 if(lowbound
> i
.name
&& i
.name
> key
) {
167 best_fn
= (void*)i
.fn
;
170 L
.pushlstring(lowbound
);
171 std::string name
= obj
->get_name() + "::" + lowbound
;
172 L
.pushvalue(lua_upvalueindex(1)); //State.
173 L
.pushlightuserdata(best_fn
);
175 L
.pushcclosure(class_info::trampoline
, 3);
183 int class_info::smethods(lua_State
* L
)
185 class_base
* obj
= (class_base
*)lua_touserdata(L
, lua_upvalueindex(1));
186 auto m
= obj
->static_methods();
189 lua_pushstring(L
, i
.name
);
195 int class_info::cmethods(lua_State
* L
)
197 class_base
* obj
= (class_base
*)lua_touserdata(L
, lua_upvalueindex(1));
198 auto m
= obj
->class_methods();
201 lua_pushstring(L
, i
.c_str());
207 typedef int (*fn_t
)(state
& L
, parameters
& P
);
209 int class_info::trampoline(lua_State
* L
)
211 state
* lstate
= reinterpret_cast<state
*>(lua_touserdata(L
, lua_upvalueindex(1)));
212 void* _fn
= lua_touserdata(L
, lua_upvalueindex(2));
214 std::string name
= lua_tostring(L
, lua_upvalueindex(3));
215 state
_L(*lstate
, L
);
217 parameters
P(_L
, name
);
219 } catch(std::exception
& e
) {
220 lua_pushfstring(L
, "%s", e
.what());
226 int lua_trampoline_function(lua_State
* L
)
228 void* ptr
= lua_touserdata(L
, lua_upvalueindex(1));
229 state
* lstate
= reinterpret_cast<state
*>(lua_touserdata(L
, lua_upvalueindex(2)));
230 function
* f
= reinterpret_cast<function
*>(ptr
);
231 state
_L(*lstate
, L
);
233 return f
->invoke(_L
);
234 } catch(std::exception
& e
) {
235 lua_pushfstring(L
, "%s", e
.what());
241 //Pushes given table to top of stack, creating if needed.
242 void recursive_lookup_table(state
& L
, const std::string
& tab
)
245 #if LUA_VERSION_NUM == 501
246 L
.pushvalue(LUA_GLOBALSINDEX
);
248 #if LUA_VERSION_NUM == 502
249 L
.rawgeti(LUA_REGISTRYINDEX
, LUA_RIDX_GLOBALS
);
251 assert(L
.type(-1) == LUA_TTABLE
);
255 size_t split
= u
.find_last_of(".");
258 if(split
< u
.length()) {
259 u1
= u
.substr(0, split
);
260 u2
= u
.substr(split
+ 1);
262 recursive_lookup_table(L
, u1
);
263 L
.getfield(-1, u2
.c_str());
264 if(L
.type(-1) != LUA_TTABLE
) {
265 //Not a table, create a table.
268 L
.setfield(-2, u2
.c_str());
269 L
.getfield(-1, u2
.c_str());
271 //Get rid of previous table.
276 void register_function(state
& L
, const std::string
& name
, function
* fun
)
278 std::string u
= name
;
279 size_t split
= u
.find_last_of(".");
282 if(split
< u
.length()) {
283 u1
= u
.substr(0, split
);
284 u2
= u
.substr(split
+ 1);
286 recursive_lookup_table(L
, u1
);
290 void* ptr
= reinterpret_cast<void*>(fun
);
291 L
.pushlightuserdata(ptr
);
292 L
.pushlightuserdata(&L
);
293 L
.pushcclosure(lua_trampoline_function
, 2);
295 L
.setfield(-2, u2
.c_str());
299 void register_class(state
& L
, const std::string
& name
, class_base
* fun
)
301 fun
->register_state(L
);
305 state::state() throw(std::bad_alloc
)
309 oom_handler
= builtin_oom
;
312 state::state(state
& _master
, lua_State
* L
)
318 state::~state() throw()
322 threads::arlock
h(get_lua_lock());
323 auto state
= state_internal_t::get_soft(this);
325 for(auto i
: state
->function_groups
)
326 i
.first
->drop_callback(i
.second
);
327 for(auto i
: state
->class_groups
)
328 i
.first
->drop_callback(i
.second
);
330 lua_close(lua_handle
);
331 state_internal_t::clear(this);
334 void state::builtin_oom()
336 std::cerr
<< "PANIC: FATAL: Out of memory" << std::endl
;
340 void* state::builtin_alloc(void* user
, void* old
, size_t olds
, size_t news
)
343 void* m
= realloc(old
, news
);
345 reinterpret_cast<state
*>(user
)->oom_handler();
353 function::function(function_group
& _group
, const std::string
& func
) throw(std::bad_alloc
)
356 group
.do_register(fname
= func
, *this);
359 function::~function() throw()
361 group
.do_unregister(fname
, *this);
364 class_base::class_base(class_group
& _group
, const std::string
& _name
)
365 : group(_group
), name(_name
)
370 class_base::~class_base() throw()
373 group
.do_unregister(name
, *this);
376 void state::reset() throw(std::bad_alloc
, std::runtime_error
)
379 return master
->reset();
380 threads::arlock
h(get_lua_lock());
381 auto state
= state_internal_t::get_soft(this);
384 lua_State
* tmp
= lua_newstate(state::builtin_alloc
, this);
386 throw std::runtime_error("Can't re-initialize Lua interpretter");
387 lua_close(lua_handle
);
388 for(auto& i
: state
->callbacks
)
393 lua_handle
= lua_newstate(state::builtin_alloc
, this);
395 throw std::runtime_error("Can't initialize Lua interpretter");
397 for(auto i
: state
->function_groups
)
398 i
.first
->request_callback([this](std::string name
, function
* func
) -> void {
399 register_function(*this, name
, func
);
401 for(auto i
: state
->class_groups
)
402 i
.first
->request_callback([this](std::string name
, class_base
* clazz
) -> void {
403 register_class(*this, name
, clazz
);
407 void state::deinit() throw()
410 return master
->deinit();
412 lua_close(lua_handle
);
416 void state::add_function_group(function_group
& group
)
418 threads::arlock
h(get_lua_lock());
419 auto& state
= state_internal_t::get(this);
420 state
.function_groups
.insert(std::make_pair(&group
, group
.add_callback([this](const std::string
& name
,
421 function
* func
) -> void {
422 this->function_callback(name
, func
);
423 }, [this](function_group
* x
) {
424 threads::arlock
h(get_lua_lock());
425 auto state
= state_internal_t::get_soft(this);
427 for(auto i
= state
->function_groups
.begin(); i
!= state
->function_groups
.end();)
429 i
= state
->function_groups
.erase(i
);
435 void state::add_class_group(class_group
& group
)
437 threads::arlock
h(get_lua_lock());
438 auto& state
= state_internal_t::get(this);
439 state
.class_groups
.insert(std::make_pair(&group
, group
.add_callback([this](const std::string
& name
,
440 class_base
* clazz
) -> void {
441 this->class_callback(name
, clazz
);
442 }, [this](class_group
* x
) {
443 threads::arlock
h(get_lua_lock());
444 auto state
= state_internal_t::get_soft(this);
446 for(auto i
= state
->class_groups
.begin(); i
!= state
->class_groups
.end();)
448 i
= state
->class_groups
.erase(i
);
454 void state::function_callback(const std::string
& name
, function
* func
)
457 return master
->function_callback(name
, func
);
459 register_function(*this, name
, func
);
462 void state::class_callback(const std::string
& name
, class_base
* clazz
)
465 return master
->class_callback(name
, clazz
);
467 register_class(*this, name
, clazz
);
470 bool state::do_once(void* key
)
473 return master
->do_once(key
);
474 pushlightuserdata(key
);
475 rawget(LUA_REGISTRYINDEX
);
476 if(type(-1) == LUA_TNIL
) {
478 pushlightuserdata(key
);
479 pushlightuserdata(key
);
480 rawset(LUA_REGISTRYINDEX
);
488 std::list
<state::callback_list
*> state::get_callbacks()
491 return master
->get_callbacks();
492 threads::arlock
h(get_lua_lock());
493 auto state
= state_internal_t::get_soft(this);
494 std::list
<callback_list
*> r
;
496 for(auto i
: state
->callbacks
)
497 r
.push_back(i
.second
);
501 void state::do_register(const std::string
& name
, callback_list
& callback
)
503 threads::arlock
h(get_lua_lock());
504 auto& state
= state_internal_t::get(this);
505 if(state
.callbacks
.count(name
)) return;
506 state
.callbacks
[name
] = &callback
;
509 void state::do_unregister(const std::string
& name
, callback_list
& callback
)
511 threads::arlock
h(get_lua_lock());
512 auto state
= state_internal_t::get_soft(this);
513 if(state
&& state
->callbacks
.count(name
) && state
->callbacks
[name
] == &callback
)
514 state
->callbacks
.erase(name
);
517 state::callback_list::callback_list(state
& _L
, const std::string
& _name
, const std::string
& fncbname
)
518 : L(_L
), name(_name
), fn_cbname(fncbname
)
520 L
.do_register(name
, *this);
523 state::callback_list::~callback_list()
525 L
.do_unregister(name
, *this);
528 for(auto& i
: callbacks
) {
529 L
.pushlightuserdata(&i
);
531 L
.rawset(LUA_REGISTRYINDEX
);
535 void state::callback_list::_register(state
& _L
)
537 callbacks
.push_back(0);
538 _L
.pushlightuserdata(&*callbacks
.rbegin());
540 _L
.rawset(LUA_REGISTRYINDEX
);
543 void state::callback_list::_unregister(state
& _L
)
545 for(auto i
= callbacks
.begin(); i
!= callbacks
.end();) {
546 _L
.pushlightuserdata(&*i
);
547 _L
.rawget(LUA_REGISTRYINDEX
);
548 if(_L
.rawequal(-1, -2)) {
550 _L
.pushlightuserdata(key
);
552 _L
.rawset(LUA_REGISTRYINDEX
);
553 i
= callbacks
.erase(i
);
560 function_group::function_group()
564 function_group::~function_group()
566 threads::arlock
h(get_lua_lock());
567 auto state
= fgroup_internal_t::get_soft(this);
569 for(auto i
: state
->dcallbacks
)
571 fgroup_internal_t::clear(this);
574 void function_group::request_callback(std::function
<void(std::string
, function
*)> cb
)
576 threads::arlock
h(get_lua_lock());
577 auto state
= fgroup_internal_t::get_soft(this);
579 for(auto i
: state
->functions
)
580 cb(i
.first
, i
.second
);
583 int function_group::add_callback(std::function
<void(std::string
, function
*)> cb
,
584 std::function
<void(function_group
*)> dcb
)
586 threads::arlock
h(get_lua_lock());
587 auto& state
= fgroup_internal_t::get(this);
588 int handle
= state
.next_handle
++;
589 state
.callbacks
[handle
] = cb
;
590 state
.dcallbacks
[handle
] = dcb
;
591 for(auto i
: state
.functions
)
592 cb(i
.first
, i
.second
);
596 void function_group::drop_callback(int handle
)
598 threads::arlock
h(get_lua_lock());
599 auto state
= fgroup_internal_t::get_soft(this);
601 state
->callbacks
.erase(handle
);
604 void function_group::do_register(const std::string
& name
, function
& fun
)
606 threads::arlock
h(get_lua_lock());
607 auto& state
= fgroup_internal_t::get(this);
608 if(state
.functions
.count(name
)) return;
609 state
.functions
[name
] = &fun
;
610 for(auto i
: state
.callbacks
)
611 i
.second(name
, &fun
);
614 void function_group::do_unregister(const std::string
& name
, function
& fun
)
616 threads::arlock
h(get_lua_lock());
617 auto state
= fgroup_internal_t::get_soft(this);
619 if(state
&& state
->functions
.count(name
) && state
->functions
[name
] == &fun
)
620 state
->functions
.erase(name
);
621 for(auto i
: state
->callbacks
)
622 i
.second(name
, NULL
);
625 class_group::class_group()
629 class_group::~class_group()
631 threads::arlock
h(get_lua_lock());
632 auto state
= cgroup_internal_t::get_soft(this);
634 for(auto i
: state
->dcallbacks
)
636 cgroup_internal_t::clear(this);
639 void class_group::request_callback(std::function
<void(std::string
, class_base
*)> cb
)
641 threads::arlock
h(get_lua_lock());
642 auto state
= cgroup_internal_t::get_soft(this);
644 for(auto i
: state
->classes
)
645 cb(i
.first
, i
.second
);
648 int class_group::add_callback(std::function
<void(std::string
, class_base
*)> cb
,
649 std::function
<void(class_group
*)> dcb
)
651 threads::arlock
h(get_lua_lock());
652 auto& state
= cgroup_internal_t::get(this);
653 int handle
= state
.next_handle
++;
654 state
.callbacks
[handle
] = cb
;
655 state
.dcallbacks
[handle
] = dcb
;
656 for(auto i
: state
.classes
)
657 cb(i
.first
, i
.second
);
661 void class_group::drop_callback(int handle
)
663 threads::arlock
h(get_lua_lock());
664 auto state
= cgroup_internal_t::get_soft(this);
666 state
->callbacks
.erase(handle
);
669 void class_group::do_register(const std::string
& name
, class_base
& fun
)
671 threads::arlock
h(get_lua_lock());
672 auto& state
= cgroup_internal_t::get(this);
673 if(state
.classes
.count(name
)) return;
674 state
.classes
[name
] = &fun
;
675 for(auto i
: state
.callbacks
)
676 i
.second(name
, &fun
);
679 void class_group::do_unregister(const std::string
& name
, class_base
& fun
)
681 threads::arlock
h(get_lua_lock());
682 auto state
= cgroup_internal_t::get_soft(this);
683 if(!state
|| !state
->classes
.count(name
) || state
->classes
[name
] != &fun
) return;
684 state
->classes
.erase(name
);
685 for(auto i
: state
->callbacks
)
686 i
.second(name
, NULL
);
689 std::list
<class_ops
>& userdata_recogn_fns()
691 static std::list
<class_ops
> x
;
695 std::string
try_recognize_userdata(state
& state
, int index
)
697 for(auto i
: userdata_recogn_fns())
698 if(i
.is(state
, index
))
700 //Hack: Lua builtin file objects and classobjs.
701 if(state
.getmetatable(index
)) {
702 state
.pushstring("FILE*");
703 state
.rawget(LUA_REGISTRYINDEX
);
704 if(state
.rawequal(-1, -2)) {
709 state
.pushlightuserdata(&classtable_meta_key
);
710 state
.rawget(LUA_REGISTRYINDEX
);
711 if(state
.rawequal(-1, -2)) {
720 std::string
try_print_userdata(state
& L
, int index
)
722 for(auto i
: userdata_recogn_fns())
724 return i
.print(L
, index
);
726 if(L
.getmetatable(index
)) {
727 L
.pushlightuserdata(&classtable_meta_key
);
728 L
.rawget(LUA_REGISTRYINDEX
);
729 if(L
.rawequal(-1, -2)) {
731 std::string cname
= ((class_info
*)L
.touserdata(index
))->obj
->get_name();
736 return "no data available";
739 int state::vararg_tag::pushargs(state
& L
)
747 else if(i
== "false")
748 L
.pushboolean(false);
749 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i
))
750 L
.pushnumber(strtod(i
.c_str(), NULL
));
752 L
.pushlstring(i
.substr(1));
760 class_base
* class_base::lookup(state
& L
, const std::string
& _name
)
762 if(lookup_and_push(L
, _name
)) {
763 class_base
* obj
= ((class_info
*)L
.touserdata(-1))->obj
;
770 bool class_base::lookup_and_push(state
& L
, const std::string
& _name
)
772 L
.pushlightuserdata(&classtable_key
);
773 L
.rawget(LUA_REGISTRYINDEX
);
774 if(L
.type(-1) == LUA_TNIL
) {
779 //On top of stack there is class table.
780 L
.pushlstring(_name
);
782 if(L
.type(-1) == LUA_TNIL
) {
792 std::set
<std::string
> class_base::all_classes(state
& L
)
794 L
.pushlightuserdata(&classtable_key
);
795 L
.rawget(LUA_REGISTRYINDEX
);
796 if(L
.type(-1) == LUA_TNIL
) {
799 return std::set
<std::string
>();
801 std::set
<std::string
> r
;
804 L
.pop(1); //Pop value.
805 if(L
.type(-1) == LUA_TSTRING
) r
.insert(L
.tostring(-1));
811 void class_base::register_static(state
& L
)
814 L
.pushlightuserdata(&classtable_key
);
815 L
.rawget(LUA_REGISTRYINDEX
);
816 if(L
.type(-1) == LUA_TNIL
) {
818 L
.pushlightuserdata(&classtable_key
);
820 L
.rawset(LUA_REGISTRYINDEX
);
823 //On top of stack there is class table.
826 if(L
.type(-1) != LUA_TNIL
) {
827 //Already registered.
833 //Now construct the object.
834 class_info
* ci
= (class_info
*)L
.newuserdata(sizeof(class_info
));
837 L
.pushlightuserdata(&classtable_meta_key
);
838 L
.rawget(LUA_REGISTRYINDEX
);
839 if(L
.type(-1) == LUA_TNIL
) {
841 L
.pushlightuserdata(&classtable_meta_key
);
843 L
.pushstring("__index");
844 L
.pushlightuserdata(&L
);
845 L
.pushcclosure(class_info::index
, 1);
847 L
.pushstring("__newindex");
848 L
.pushcfunction(class_info::newindex
);
850 L
.pushstring("__pairs");
851 L
.pushlightuserdata(&L
);
852 L
.pushcclosure(class_info::pairs
, 1);
854 L
.rawset(LUA_REGISTRYINDEX
);
862 void class_base::delayed_register()
864 group
.do_register(name
, *this);
867 functions::functions(function_group
& grp
, const std::string
& basetable
, std::initializer_list
<entry
> fnlist
)
869 std::string base
= (basetable
== "") ? "" : (basetable
+ ".");
871 funcs
.insert(new fn(grp
, base
+ i
.name
, i
.func
));
874 functions::~functions()
880 functions::fn::fn(function_group
& grp
, const std::string
& name
, std::function
<int(state
& L
, parameters
& P
)> _func
)
881 : function(grp
, name
)
886 functions::fn::~fn() throw()
890 int functions::fn::invoke(state
& L
)
892 lua::parameters
P(L
, fname
);