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));
215 std::string name
= lua_tostring(L
, lua_upvalueindex(3));
216 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
);
232 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
)
246 assert(L
.type(-1) == LUA_TTABLE
);
250 size_t split
= u
.find_last_of(".");
253 if(split
< u
.length()) {
254 u1
= u
.substr(0, split
);
255 u2
= u
.substr(split
+ 1);
257 recursive_lookup_table(L
, u1
);
258 L
.getfield(-1, u2
.c_str());
259 if(L
.type(-1) != LUA_TTABLE
) {
260 //Not a table, create a table.
263 L
.setfield(-2, u2
.c_str());
264 L
.getfield(-1, u2
.c_str());
266 //Get rid of previous table.
271 void register_function(state
& L
, const std::string
& name
, function
* fun
)
273 std::string u
= name
;
274 size_t split
= u
.find_last_of(".");
277 if(split
< u
.length()) {
278 u1
= u
.substr(0, split
);
279 u2
= u
.substr(split
+ 1);
281 recursive_lookup_table(L
, u1
);
285 void* ptr
= reinterpret_cast<void*>(fun
);
286 L
.pushlightuserdata(ptr
);
287 L
.pushlightuserdata(&L
);
288 L
.pushcclosure(lua_trampoline_function
, 2);
290 L
.setfield(-2, u2
.c_str());
294 void register_class(state
& L
, const std::string
& name
, class_base
* fun
)
296 fun
->register_state(L
);
300 state::state() throw(std::bad_alloc
)
304 oom_handler
= builtin_oom
;
307 state::state(state
& _master
, lua_State
* L
)
313 state::~state() throw()
317 threads::arlock
h(get_lua_lock());
318 auto state
= state_internal_t::get_soft(this);
320 for(auto i
: state
->function_groups
)
321 i
.first
->drop_callback(i
.second
);
322 for(auto i
: state
->class_groups
)
323 i
.first
->drop_callback(i
.second
);
325 lua_close(lua_handle
);
326 state_internal_t::clear(this);
329 void state::builtin_oom()
331 std::cerr
<< "PANIC: FATAL: Out of memory" << std::endl
;
335 void* state::builtin_alloc(void* user
, void* old
, size_t olds
, size_t news
)
338 void* m
= realloc(old
, news
);
340 reinterpret_cast<state
*>(user
)->oom_handler();
348 function::function(function_group
& _group
, const std::string
& func
) throw(std::bad_alloc
)
351 group
.do_register(fname
= func
, *this);
354 function::~function() throw()
356 group
.do_unregister(fname
, *this);
359 class_base::class_base(class_group
& _group
, const std::string
& _name
)
360 : group(_group
), name(_name
)
365 class_base::~class_base() throw()
368 group
.do_unregister(name
, *this);
371 void state::reset() throw(std::bad_alloc
, std::runtime_error
)
374 return master
->reset();
375 threads::arlock
h(get_lua_lock());
376 auto state
= &state_internal_t::get(this);
378 lua_State
* tmp
= lua_newstate(state::builtin_alloc
, this);
380 throw std::runtime_error("Can't re-initialize Lua interpretter");
381 lua_close(lua_handle
);
382 for(auto& i
: state
->callbacks
)
387 lua_handle
= lua_newstate(state::builtin_alloc
, this);
389 throw std::runtime_error("Can't initialize Lua interpretter");
391 for(auto i
: state
->function_groups
)
392 i
.first
->request_callback([this](std::string name
, function
* func
) -> void {
393 register_function(*this, name
, func
);
395 for(auto i
: state
->class_groups
)
396 i
.first
->request_callback([this](std::string name
, class_base
* clazz
) -> void {
397 register_class(*this, name
, clazz
);
401 void state::deinit() throw()
404 return master
->deinit();
406 lua_close(lua_handle
);
410 void state::add_function_group(function_group
& group
)
412 threads::arlock
h(get_lua_lock());
413 auto& state
= state_internal_t::get(this);
414 state
.function_groups
.insert(std::make_pair(&group
, group
.add_callback([this](const std::string
& name
,
415 function
* func
) -> void {
416 this->function_callback(name
, func
);
417 }, [this](function_group
* x
) {
418 threads::arlock
h(get_lua_lock());
419 auto state
= state_internal_t::get_soft(this);
421 for(auto i
= state
->function_groups
.begin(); i
!= state
->function_groups
.end();)
423 i
= state
->function_groups
.erase(i
);
429 void state::add_class_group(class_group
& group
)
431 threads::arlock
h(get_lua_lock());
432 auto& state
= state_internal_t::get(this);
433 state
.class_groups
.insert(std::make_pair(&group
, group
.add_callback([this](const std::string
& name
,
434 class_base
* clazz
) -> void {
435 this->class_callback(name
, clazz
);
436 }, [this](class_group
* x
) {
437 threads::arlock
h(get_lua_lock());
438 auto state
= state_internal_t::get_soft(this);
440 for(auto i
= state
->class_groups
.begin(); i
!= state
->class_groups
.end();)
442 i
= state
->class_groups
.erase(i
);
448 void state::function_callback(const std::string
& name
, function
* func
)
451 return master
->function_callback(name
, func
);
453 register_function(*this, name
, func
);
456 void state::class_callback(const std::string
& name
, class_base
* clazz
)
459 return master
->class_callback(name
, clazz
);
461 register_class(*this, name
, clazz
);
464 bool state::do_once(void* key
)
467 return master
->do_once(key
);
468 pushlightuserdata(key
);
469 rawget(LUA_REGISTRYINDEX
);
470 if(type(-1) == LUA_TNIL
) {
472 pushlightuserdata(key
);
473 pushlightuserdata(key
);
474 rawset(LUA_REGISTRYINDEX
);
482 std::list
<state::callback_list
*> state::get_callbacks()
485 return master
->get_callbacks();
486 threads::arlock
h(get_lua_lock());
487 auto state
= state_internal_t::get_soft(this);
488 std::list
<callback_list
*> r
;
490 for(auto i
: state
->callbacks
)
491 r
.push_back(i
.second
);
495 void state::do_register(const std::string
& name
, callback_list
& callback
)
497 threads::arlock
h(get_lua_lock());
498 auto& state
= state_internal_t::get(this);
499 if(state
.callbacks
.count(name
)) return;
500 state
.callbacks
[name
] = &callback
;
503 void state::do_unregister(const std::string
& name
, callback_list
& callback
)
505 threads::arlock
h(get_lua_lock());
506 auto state
= state_internal_t::get_soft(this);
507 if(state
&& state
->callbacks
.count(name
) && state
->callbacks
[name
] == &callback
)
508 state
->callbacks
.erase(name
);
511 state::callback_list::callback_list(state
& _L
, const std::string
& _name
, const std::string
& fncbname
)
512 : L(_L
), name(_name
), fn_cbname(fncbname
)
514 L
.do_register(name
, *this);
517 state::callback_list::~callback_list()
519 L
.do_unregister(name
, *this);
522 for(auto& i
: callbacks
) {
523 L
.pushlightuserdata(&i
);
525 L
.rawset(LUA_REGISTRYINDEX
);
529 void state::callback_list::_register(state
& _L
)
531 callbacks
.push_back(0);
532 _L
.pushlightuserdata(&*callbacks
.rbegin());
534 _L
.rawset(LUA_REGISTRYINDEX
);
537 void state::callback_list::_unregister(state
& _L
)
539 for(auto i
= callbacks
.begin(); i
!= callbacks
.end();) {
540 _L
.pushlightuserdata(&*i
);
541 _L
.rawget(LUA_REGISTRYINDEX
);
542 if(_L
.rawequal(-1, -2)) {
544 _L
.pushlightuserdata(key
);
546 _L
.rawset(LUA_REGISTRYINDEX
);
547 i
= callbacks
.erase(i
);
554 function_group::function_group()
558 function_group::~function_group()
560 threads::arlock
h(get_lua_lock());
561 auto state
= fgroup_internal_t::get_soft(this);
563 for(auto i
: state
->dcallbacks
)
565 fgroup_internal_t::clear(this);
568 void function_group::request_callback(std::function
<void(std::string
, function
*)> cb
)
570 threads::arlock
h(get_lua_lock());
571 auto state
= fgroup_internal_t::get_soft(this);
573 for(auto i
: state
->functions
)
574 cb(i
.first
, i
.second
);
577 int function_group::add_callback(std::function
<void(std::string
, function
*)> cb
,
578 std::function
<void(function_group
*)> dcb
)
580 threads::arlock
h(get_lua_lock());
581 auto& state
= fgroup_internal_t::get(this);
582 int handle
= state
.next_handle
++;
583 state
.callbacks
[handle
] = cb
;
584 state
.dcallbacks
[handle
] = dcb
;
585 for(auto i
: state
.functions
)
586 cb(i
.first
, i
.second
);
590 void function_group::drop_callback(int handle
)
592 threads::arlock
h(get_lua_lock());
593 auto state
= fgroup_internal_t::get_soft(this);
595 state
->callbacks
.erase(handle
);
598 void function_group::do_register(const std::string
& name
, function
& fun
)
600 threads::arlock
h(get_lua_lock());
601 auto& state
= fgroup_internal_t::get(this);
602 if(state
.functions
.count(name
)) return;
603 state
.functions
[name
] = &fun
;
604 for(auto i
: state
.callbacks
)
605 i
.second(name
, &fun
);
608 void function_group::do_unregister(const std::string
& name
, function
& fun
)
610 threads::arlock
h(get_lua_lock());
611 auto state
= fgroup_internal_t::get_soft(this);
612 if(!state
|| !state
->functions
.count(name
) || state
->functions
[name
] != &fun
) return;
613 state
->functions
.erase(name
);
614 for(auto i
: state
->callbacks
)
615 i
.second(name
, NULL
);
618 class_group::class_group()
622 class_group::~class_group()
624 threads::arlock
h(get_lua_lock());
625 auto state
= cgroup_internal_t::get_soft(this);
627 for(auto i
: state
->dcallbacks
)
629 cgroup_internal_t::clear(this);
632 void class_group::request_callback(std::function
<void(std::string
, class_base
*)> cb
)
634 threads::arlock
h(get_lua_lock());
635 auto state
= cgroup_internal_t::get_soft(this);
637 for(auto i
: state
->classes
)
638 cb(i
.first
, i
.second
);
641 int class_group::add_callback(std::function
<void(std::string
, class_base
*)> cb
,
642 std::function
<void(class_group
*)> dcb
)
644 threads::arlock
h(get_lua_lock());
645 auto& state
= cgroup_internal_t::get(this);
646 int handle
= state
.next_handle
++;
647 state
.callbacks
[handle
] = cb
;
648 state
.dcallbacks
[handle
] = dcb
;
649 for(auto i
: state
.classes
)
650 cb(i
.first
, i
.second
);
654 void class_group::drop_callback(int handle
)
656 threads::arlock
h(get_lua_lock());
657 auto state
= cgroup_internal_t::get_soft(this);
659 state
->callbacks
.erase(handle
);
662 void class_group::do_register(const std::string
& name
, class_base
& fun
)
664 threads::arlock
h(get_lua_lock());
665 auto& state
= cgroup_internal_t::get(this);
666 if(state
.classes
.count(name
)) return;
667 state
.classes
[name
] = &fun
;
668 for(auto i
: state
.callbacks
)
669 i
.second(name
, &fun
);
672 void class_group::do_unregister(const std::string
& name
, class_base
& fun
)
674 threads::arlock
h(get_lua_lock());
675 auto state
= cgroup_internal_t::get_soft(this);
676 if(!state
|| !state
->classes
.count(name
) || state
->classes
[name
] != &fun
) return;
677 state
->classes
.erase(name
);
678 for(auto i
: state
->callbacks
)
679 i
.second(name
, NULL
);
682 std::list
<class_ops
>& userdata_recogn_fns()
684 static std::list
<class_ops
> x
;
688 std::string
try_recognize_userdata(state
& state
, int index
)
690 for(auto i
: userdata_recogn_fns())
691 if(i
.is(state
, index
))
693 //Hack: Lua builtin file objects and classobjs.
694 if(state
.getmetatable(index
)) {
695 state
.pushstring("FILE*");
696 state
.rawget(LUA_REGISTRYINDEX
);
697 if(state
.rawequal(-1, -2)) {
702 state
.pushlightuserdata(&classtable_meta_key
);
703 state
.rawget(LUA_REGISTRYINDEX
);
704 if(state
.rawequal(-1, -2)) {
713 std::string
try_print_userdata(state
& L
, int index
)
715 for(auto i
: userdata_recogn_fns())
717 return i
.print(L
, index
);
719 if(L
.getmetatable(index
)) {
720 L
.pushlightuserdata(&classtable_meta_key
);
721 L
.rawget(LUA_REGISTRYINDEX
);
722 if(L
.rawequal(-1, -2)) {
724 std::string cname
= ((class_info
*)L
.touserdata(index
))->obj
->get_name();
729 return "no data available";
732 int state::vararg_tag::pushargs(state
& L
)
740 else if(i
== "false")
741 L
.pushboolean(false);
742 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i
))
743 L
.pushnumber(strtod(i
.c_str(), NULL
));
745 L
.pushlstring(i
.substr(1));
753 class_base
* class_base::lookup(state
& L
, const std::string
& _name
)
755 if(lookup_and_push(L
, _name
)) {
756 class_base
* obj
= ((class_info
*)L
.touserdata(-1))->obj
;
763 bool class_base::lookup_and_push(state
& L
, const std::string
& _name
)
765 L
.pushlightuserdata(&classtable_key
);
766 L
.rawget(LUA_REGISTRYINDEX
);
767 if(L
.type(-1) == LUA_TNIL
) {
772 //On top of stack there is class table.
773 L
.pushlstring(_name
);
775 if(L
.type(-1) == LUA_TNIL
) {
785 std::set
<std::string
> class_base::all_classes(state
& L
)
787 L
.pushlightuserdata(&classtable_key
);
788 L
.rawget(LUA_REGISTRYINDEX
);
789 if(L
.type(-1) == LUA_TNIL
) {
792 return std::set
<std::string
>();
794 std::set
<std::string
> r
;
797 L
.pop(1); //Pop value.
798 if(L
.type(-1) == LUA_TSTRING
) r
.insert(L
.tostring(-1));
804 void class_base::register_static(state
& L
)
807 L
.pushlightuserdata(&classtable_key
);
808 L
.rawget(LUA_REGISTRYINDEX
);
809 if(L
.type(-1) == LUA_TNIL
) {
811 L
.pushlightuserdata(&classtable_key
);
813 L
.rawset(LUA_REGISTRYINDEX
);
816 //On top of stack there is class table.
819 if(L
.type(-1) != LUA_TNIL
) {
820 //Already registered.
826 //Now construct the object.
827 class_info
* ci
= (class_info
*)L
.newuserdata(sizeof(class_info
));
830 L
.pushlightuserdata(&classtable_meta_key
);
831 L
.rawget(LUA_REGISTRYINDEX
);
832 if(L
.type(-1) == LUA_TNIL
) {
834 L
.pushlightuserdata(&classtable_meta_key
);
836 L
.pushstring("__index");
837 L
.pushlightuserdata(&L
);
838 L
.pushcclosure(class_info::index
, 1);
840 L
.pushstring("__newindex");
841 L
.pushcfunction(class_info::newindex
);
843 L
.pushstring("__pairs");
844 L
.pushlightuserdata(&L
);
845 L
.pushcclosure(class_info::pairs
, 1);
847 L
.rawset(LUA_REGISTRYINDEX
);
855 void class_base::delayed_register()
857 group
.do_register(name
, *this);
860 functions::functions(function_group
& grp
, const std::string
& basetable
, std::initializer_list
<entry
> fnlist
)
862 std::string base
= (basetable
== "") ? "" : (basetable
+ ".");
864 funcs
.insert(new fn(grp
, base
+ i
.name
, i
.func
));
867 functions::~functions()
873 functions::fn::fn(function_group
& grp
, const std::string
& name
, std::function
<int(state
& L
, parameters
& P
)> _func
)
874 : function(grp
, name
)
879 functions::fn::~fn() throw()
883 int functions::fn::invoke(state
& L
)
885 lua::parameters
P(L
, fname
);