Actually call on_reset callback
[lsnes.git] / src / library / lua.cpp
blob3fa154a1820834c8804b12a47f13128ebc1b35ec
1 #include "lua-base.hpp"
2 #include "lua-class.hpp"
3 #include "lua-function.hpp"
4 #include "lua-params.hpp"
5 #include "lua-pin.hpp"
6 #include "stateobject.hpp"
7 #include "threads.hpp"
8 #include <functional>
9 #include <iostream>
10 #include <cassert>
12 namespace lua
14 namespace
16 threads::rlock* global_lock;
17 threads::rlock& get_lua_lock()
19 if(!global_lock) global_lock = new threads::rlock;
20 return *global_lock;
23 struct state_internal
25 std::map<std::string, state::callback_list*> callbacks;
26 std::set<std::pair<function_group*, int>> function_groups;
27 std::set<std::pair<class_group*, int>> class_groups;
30 struct fgroup_internal
32 fgroup_internal()
34 next_handle = 0;
36 std::map<std::string, function*> functions;
37 int next_handle;
38 std::map<int, std::function<void(std::string, function*)>> callbacks;
39 std::map<int, std::function<void(function_group*)>> dcallbacks;
42 struct cgroup_internal
44 cgroup_internal()
46 next_handle = 0;
48 int next_handle;
49 std::map<std::string, class_base*> classes;
50 std::map<int, std::function<void(std::string, class_base*)>> callbacks;
51 std::map<int, std::function<void(class_group*)>> dcallbacks;
54 typedef stateobject::type<state, state_internal> state_internal_t;
55 typedef stateobject::type<function_group, fgroup_internal> fgroup_internal_t;
56 typedef stateobject::type<class_group, cgroup_internal> cgroup_internal_t;
59 std::unordered_map<std::type_index, void*>& class_types()
61 static std::unordered_map<std::type_index, void*> x;
62 return x;
64 namespace
66 char classtable_key;
67 char classtable_meta_key;
69 struct class_info
71 class_base* obj;
72 static int index(state& L);
73 static int newindex(state& L);
74 static int pairs(state& L);
75 static int pairs_next(state& L);
76 static int smethods(state& L);
77 static int cmethods(state& L);
78 static int trampoline(state& L);
79 static void check(state& L);
82 void class_info::check(state& L)
84 L.pushlightuserdata(&classtable_meta_key);
85 L.rawget(LUA_REGISTRYINDEX);
86 L.getmetatable(1);
87 if(!L.rawequal(-1, -2))
88 throw std::runtime_error("Bad class table");
89 L.pop(2);
92 int class_info::index(state& L)
94 check(L);
96 class_base* ptr = ((class_info*)L.touserdata(1))->obj;
97 const char* method = L.tostring(2);
98 if(!method)
99 throw std::runtime_error("Indexing invalid element of class table");
100 if(!strcmp(method, "_static_methods")) {
101 L.pushlightuserdata(ptr);
102 L.push_trampoline(class_info::smethods, 1);
103 return 1;
104 } else if(!strcmp(method, "_class_methods")) {
105 L.pushlightuserdata(ptr);
106 L.push_trampoline(class_info::cmethods, 1);
107 return 1;
108 } else {
109 auto m = ptr->static_methods();
110 for(auto i : m) {
111 if(!strcmp(i.name, method)) {
112 //Hit.
113 std::string fname = ptr->get_name() + "::" + i.name;
114 L.pushlightuserdata((void*)i.fn);
115 L.pushstring(fname.c_str());
116 L.push_trampoline(class_info::trampoline, 2);
117 return 1;
120 std::string err = std::string("Class '") + ptr->get_name() +
121 "' does not have static method '" + method + "'";
122 throw std::runtime_error(err);
124 return 0; //NOTREACHED
126 int class_info::newindex(state& L)
128 throw std::runtime_error("Writing into class table not allowed");
131 int class_info::pairs(state& L)
133 check(L);
135 L.push_trampoline(class_info::pairs_next, 0); //Next.
136 L.pushvalue(1); //State.
137 L.pushnil(); //Index.
138 return 3;
141 int class_info::pairs_next(state& L)
143 check(L);
145 class_base* obj = ((class_info*)L.touserdata(1))->obj;
146 auto m = obj->static_methods();
147 std::string key = (L.type(2) == LUA_TSTRING) ? L.tostring(2) : "";
148 std::string lowbound = "\xFF"; //Sorts greater than anything that is valid UTF-8.
149 void* best_fn = NULL;
150 for(auto i : m)
151 if(lowbound > i.name && i.name > key) {
152 lowbound = i.name;
153 best_fn = (void*)i.fn;
155 if(best_fn) {
156 L.pushlstring(lowbound);
157 std::string name = obj->get_name() + "::" + lowbound;
158 L.pushlightuserdata(best_fn);
159 L.pushlstring(name);
160 L.push_trampoline(class_info::trampoline, 2);
161 return 2;
162 } else {
163 L.pushnil();
164 return 1;
168 int class_info::smethods(state& L)
170 class_base* obj = (class_base*)L.touserdata(L.trampoline_upval(1));
171 auto m = obj->static_methods();
172 int rets = 0;
173 for(auto i : m) {
174 L.pushstring(i.name);
175 rets++;
177 return rets;
180 int class_info::cmethods(state& L)
182 class_base* obj = (class_base*)L.touserdata(L.trampoline_upval(1));
183 auto m = obj->class_methods();
184 int rets = 0;
185 for(auto i : m) {
186 L.pushstring(i.c_str());
187 rets++;
189 return rets;
192 typedef int (*fn_t)(state& L, parameters& P);
193 typedef int (*fnraw_t)(state& L);
195 //2 upvalues:
196 //1) Pointer to function control block.
197 //2) Pointer to method name.
198 int class_info::trampoline(state& L)
200 void* _fn = L.touserdata(L.trampoline_upval(1));
201 fn_t fn = (fn_t)_fn;
202 std::string name = L.tostring(L.trampoline_upval(2));
203 parameters P(L, name);
204 return fn(L, P);
207 //1 upvalue:
208 //1) Pointer to function control block.
209 int lua_trampoline_function(state& L)
211 void* ptr = L.touserdata(L.trampoline_upval(1));
212 function* f = reinterpret_cast<function*>(ptr);
213 return f->invoke(L);
216 //2 upvalues.
217 //1) Pointer to master state.
218 //2) Poiinter to function to call.
219 int lua_main_trampoline(lua_State* L)
221 state* lstate = reinterpret_cast<state*>(lua_touserdata(L, lua_upvalueindex(1)));
222 void* _fn = lua_touserdata(L, lua_upvalueindex(2));
223 fnraw_t fn = (fnraw_t)_fn;
224 //The function is always run in non-set_interruptable mode.
225 try {
226 state _L(*lstate, L);
227 lstate->set_interruptable_flag(false);
228 int r = fn(_L);
229 lstate->set_interruptable_flag(true);
230 return r;
231 } catch(std::exception& e) {
232 lua_pushfstring(L, "%s", e.what());
233 lstate->set_interruptable_flag(true);
234 lua_error(L);
236 return 0;
239 //Pushes given table to top of stack, creating if needed.
240 void recursive_lookup_table(state& L, const std::string& tab)
242 if(tab == "") {
243 L.pushglobals();
244 assert(L.type(-1) == LUA_TTABLE);
245 return;
247 std::string u = tab;
248 size_t split = u.find_last_of(".");
249 std::string u1;
250 std::string u2 = u;
251 if(split < u.length()) {
252 u1 = u.substr(0, split);
253 u2 = u.substr(split + 1);
255 recursive_lookup_table(L, u1);
256 L.getfield(-1, u2.c_str());
257 if(L.type(-1) != LUA_TTABLE) {
258 //Not a table, create a table.
259 L.pop(1);
260 L.newtable();
261 L.setfield(-2, u2.c_str());
262 L.getfield(-1, u2.c_str());
264 //Get rid of previous table.
265 L.insert(-2);
266 L.pop(1);
269 void register_function(state& L, const std::string& name, function* fun)
271 std::string u = name;
272 size_t split = u.find_last_of(".");
273 std::string u1;
274 std::string u2 = u;
275 if(split < u.length()) {
276 u1 = u.substr(0, split);
277 u2 = u.substr(split + 1);
279 recursive_lookup_table(L, u1);
280 if(!fun)
281 L.pushnil();
282 else {
283 void* ptr = reinterpret_cast<void*>(fun);
284 L.pushlightuserdata(ptr);
285 L.push_trampoline(lua_trampoline_function, 1);
287 L.setfield(-2, u2.c_str());
288 L.pop(1);
291 void register_class(state& L, const std::string& name, class_base* fun)
293 fun->register_state(L);
296 int run_interruptable_trampoline(lua_State* L)
298 //Be very careful with faults here! We are running in interruptable context.
299 static std::string err;
300 auto& fn = *(std::function<void()>*)lua_touserdata(L, -1);
301 int out = lua_tonumber(L, -2);
302 lua_pop(L, 2); //fn is passed as a pointer, so popping it is OK.
303 try {
304 fn();
305 } catch(std::exception& e) {
306 err = e.what();
307 //This can fault, so err is static.
308 lua_pushlstring(L, err.c_str(), err.length());
309 lua_error(L);
311 return out;
315 state::state()
317 master = NULL;
318 lua_handle = NULL;
319 oom_handler = builtin_oom;
320 soft_oom_handler = builtin_soft_oom;
321 interruptable = false; //Assume initially not interruptable.
322 memory_limit = (size_t)-1; //Unlimited.
323 memory_use = 0;
326 state::state(state& _master, lua_State* L)
328 master = &_master;
329 lua_handle = L;
332 state::~state() throw()
334 if(master)
335 return;
336 threads::arlock h(get_lua_lock());
337 auto state = state_internal_t::get_soft(this);
338 if(!state) return;
339 for(auto i : state->function_groups)
340 i.first->drop_callback(i.second);
341 for(auto i : state->class_groups)
342 i.first->drop_callback(i.second);
343 if(lua_handle)
344 lua_close(lua_handle);
345 state_internal_t::clear(this);
348 void state::builtin_oom()
350 std::cerr << "PANIC: FATAL: Out of memory" << std::endl;
351 exit(1);
354 void state::builtin_soft_oom(int status)
356 if(status == 0)
357 std::cerr << "Lua: Memory limit exceeded, attempting to free memory..." << std::endl;
358 if(status < 0)
359 std::cerr << "Lua: Memory allocation still failed." << std::endl;
360 if(status > 0)
361 std::cerr << "Lua: Allocation successful after freeing some memory." << std::endl;
364 void* state::builtin_alloc(void* user, void* old, size_t olds, size_t news)
366 void* m;
367 auto& st = *reinterpret_cast<state*>(user);
368 if(news) {
369 if(news > olds && !st.charge_memory(news - olds, false)) {
370 goto retry_allocation;
372 m = realloc(old, news);
373 if(!m && !st.get_interruptable_flag())
374 st.oom_handler();
375 if(!m) {
376 st.charge_memory(news - olds, true); //Undo commit.
377 goto retry_allocation;
379 if(news < olds)
380 st.charge_memory(olds - news, true); //Release memory.
381 if(m && st.memory_change) st.memory_change((ssize_t)news - (ssize_t)olds);
382 return m;
383 } else {
384 st.charge_memory(olds, true); //Release memory.
385 if(st.memory_change) st.memory_change(-(ssize_t)olds);
386 free(old);
388 return NULL;
389 retry_allocation:
390 st.soft_oom_handler(0);
391 st.interruptable = false; //Give everything we got for the GC.
392 lua_gc(st.lua_handle, LUA_GCCOLLECT,0); //Do full cycle to try to free some memory.
393 st.interruptable = true;
394 if(!st.charge_memory(news - olds, false)) { //Try to see if memory can be allocated.
395 st.soft_oom_handler(-1);
396 return NULL;
398 m = realloc(old, news);
399 if(!m && news > olds)
400 st.charge_memory(news - olds, true); //Undo commit.
401 st.soft_oom_handler(m ? 1 : -1);
402 if(m && st.memory_change) st.memory_change((ssize_t)news - (ssize_t)olds);
403 return m;
406 void state::push_trampoline(int(*fn)(state& L), unsigned n_upvals)
408 lua_pushlightuserdata(lua_handle, (void*)&get_master());
409 lua_pushlightuserdata(lua_handle, (void*)fn);
410 if(n_upvals > 0) {
411 lua_insert(lua_handle, -(int)n_upvals - 2);
412 lua_insert(lua_handle, -(int)n_upvals - 2);
414 lua_pushcclosure(lua_handle, lua_main_trampoline, trampoline_upvals + n_upvals);
417 //Lua 5.1 doesn't define LUA_OK.
418 #ifndef LUA_OK
419 #define LUA_OK 0
420 #endif
422 void state::run_interruptable(std::function<void()> fn, unsigned in, unsigned out)
424 pushnumber(out);
425 pushlightuserdata(&fn);
426 pushcfunction(run_interruptable_trampoline);
427 insert(-(int)in - 3);
428 int r = pcall(in + 2, out, 0);
429 if(r == LUA_OK) {
430 //Nothing.
431 } else if(r == LUA_ERRRUN) {
432 throw std::runtime_error(tostring(-1));
433 } else if(r == LUA_ERRMEM) {
434 throw std::runtime_error("Lua out of memory");
435 } else if(r == LUA_ERRERR) {
436 throw std::runtime_error("Lua double fault");
437 #ifdef LUA_ERRGCMM
438 } else if(r == LUA_ERRGCMM) {
439 throw std::runtime_error("Lua fault in garbage collector");
440 #endif
444 bool state::charge_memory(size_t amount, bool release)
446 if(master) return master->charge_memory(amount, release);
447 if(release) {
448 if(memory_use > amount)
449 memory_use -= amount;
450 else
451 memory_use = 0;
452 return true;
454 if(!interruptable) {
455 //Give everything we got.
456 memory_use += amount;
457 return true;
458 } else {
459 //Check limit and refuse allocations too large.
460 if(memory_use + amount > memory_limit || memory_use + amount < amount)
461 return false;
462 memory_use += amount;
463 return true;
467 function::function(function_group& _group, const std::string& func)
468 : group(_group)
470 group.do_register(fname = func, *this);
473 function::~function() throw()
475 group.do_unregister(fname, *this);
478 class_base::class_base(class_group& _group, const std::string& _name)
479 : group(_group), name(_name)
481 registered = false;
484 class_base::~class_base() throw()
486 if(registered)
487 group.do_unregister(name, *this);
490 void state::reset()
492 if(master)
493 return master->reset();
494 threads::arlock h(get_lua_lock());
495 auto state = &state_internal_t::get(this);
496 if(lua_handle) {
497 lua_State* tmp = lua_newstate(state::builtin_alloc, this);
498 if(!tmp)
499 throw std::runtime_error("Can't re-initialize Lua interpretter");
500 lua_close(lua_handle);
501 for(auto& i : state->callbacks)
502 i.second->clear();
503 lua_handle = tmp;
504 } else {
505 //Initialize new.
506 lua_handle = lua_newstate(state::builtin_alloc, this);
507 if(!lua_handle)
508 throw std::runtime_error("Can't initialize Lua interpretter");
510 for(auto i : state->function_groups)
511 i.first->request_callback([this](std::string name, function* func) -> void {
512 register_function(*this, name, func);
514 for(auto i : state->class_groups)
515 i.first->request_callback([this](std::string name, class_base* clazz) -> void {
516 register_class(*this, name, clazz);
520 void state::deinit() throw()
522 if(master)
523 return master->deinit();
524 if(lua_handle)
525 lua_close(lua_handle);
526 lua_handle = NULL;
529 void state::add_function_group(function_group& group)
531 threads::arlock h(get_lua_lock());
532 auto& state = state_internal_t::get(this);
533 state.function_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
534 function* func) -> void {
535 this->function_callback(name, func);
536 }, [this](function_group* x) {
537 threads::arlock h(get_lua_lock());
538 auto state = state_internal_t::get_soft(this);
539 if(!state) return;
540 for(auto i = state->function_groups.begin(); i != state->function_groups.end();)
541 if(i->first == x)
542 i = state->function_groups.erase(i);
543 else
544 i++;
545 })));
548 void state::add_class_group(class_group& group)
550 threads::arlock h(get_lua_lock());
551 auto& state = state_internal_t::get(this);
552 state.class_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
553 class_base* clazz) -> void {
554 this->class_callback(name, clazz);
555 }, [this](class_group* x) {
556 threads::arlock h(get_lua_lock());
557 auto state = state_internal_t::get_soft(this);
558 if(!state) return;
559 for(auto i = state->class_groups.begin(); i != state->class_groups.end();)
560 if(i->first == x)
561 i = state->class_groups.erase(i);
562 else
563 i++;
564 })));
567 void state::function_callback(const std::string& name, function* func)
569 if(master)
570 return master->function_callback(name, func);
571 if(lua_handle)
572 register_function(*this, name, func);
575 void state::class_callback(const std::string& name, class_base* clazz)
577 if(master)
578 return master->class_callback(name, clazz);
579 if(lua_handle)
580 register_class(*this, name, clazz);
583 bool state::do_once(void* key)
585 if(master)
586 return master->do_once(key);
587 pushlightuserdata(key);
588 rawget(LUA_REGISTRYINDEX);
589 if(type(-1) == LUA_TNIL) {
590 pop(1);
591 pushlightuserdata(key);
592 pushlightuserdata(key);
593 rawset(LUA_REGISTRYINDEX);
594 return true;
595 } else {
596 pop(1);
597 return false;
601 std::list<state::callback_list*> state::get_callbacks()
603 if(master)
604 return master->get_callbacks();
605 threads::arlock h(get_lua_lock());
606 auto state = state_internal_t::get_soft(this);
607 std::list<callback_list*> r;
608 if(state)
609 for(auto i : state->callbacks)
610 r.push_back(i.second);
611 return r;
614 void state::do_register(const std::string& name, callback_list& callback)
616 threads::arlock h(get_lua_lock());
617 auto& state = state_internal_t::get(this);
618 if(state.callbacks.count(name)) return;
619 state.callbacks[name] = &callback;
622 void state::do_unregister(const std::string& name, callback_list& callback)
624 threads::arlock h(get_lua_lock());
625 auto state = state_internal_t::get_soft(this);
626 if(state && state->callbacks.count(name) && state->callbacks[name] == &callback)
627 state->callbacks.erase(name);
630 state::callback_list::callback_list(state& _L, const std::string& _name, const std::string& fncbname)
631 : L(_L), name(_name), fn_cbname(fncbname)
633 running_cb = NULL;
634 running_cb_f = false;
635 L.do_register(name, *this);
638 state::callback_list::~callback_list()
640 L.do_unregister(name, *this);
641 if(!L.handle())
642 return;
643 for(auto& i : callbacks) {
644 L.pushlightuserdata(&i);
645 L.pushnil();
646 L.rawset(LUA_REGISTRYINDEX);
650 void state::callback_list::_register(state& _L)
652 callbacks.push_back(0);
653 _L.pushlightuserdata(&*callbacks.rbegin());
654 _L.pushvalue(-2);
655 _L.rawset(LUA_REGISTRYINDEX);
658 void state::callback_list::_unregister(state& _L)
660 for(auto i = callbacks.begin(); i != callbacks.end();) {
661 _L.pushlightuserdata(&*i);
662 _L.rawget(LUA_REGISTRYINDEX);
663 if(_L.rawequal(-1, -2)) {
664 char* key = &*i;
665 _L.pushlightuserdata(key);
666 _L.pushnil();
667 _L.rawset(LUA_REGISTRYINDEX);
668 if(running_cb == &*i) {
669 //Unregistering currently running callback. Delay erasing the node until the
670 //callback finishes to avoid crashes.
671 running_cb_f = true;
672 i++;
673 } else {
674 i = callbacks.erase(i);
676 } else
677 i++;
678 _L.pop(1);
682 function_group::function_group()
686 function_group::~function_group()
688 threads::arlock h(get_lua_lock());
689 auto state = fgroup_internal_t::get_soft(this);
690 if(!state) return;
691 for(auto i : state->dcallbacks)
692 i.second(this);
693 fgroup_internal_t::clear(this);
696 void function_group::request_callback(std::function<void(std::string, function*)> cb)
698 threads::arlock h(get_lua_lock());
699 auto state = fgroup_internal_t::get_soft(this);
700 if(!state) return;
701 for(auto i : state->functions)
702 cb(i.first, i.second);
705 int function_group::add_callback(std::function<void(std::string, function*)> cb,
706 std::function<void(function_group*)> dcb)
708 threads::arlock h(get_lua_lock());
709 auto& state = fgroup_internal_t::get(this);
710 int handle = state.next_handle++;
711 state.callbacks[handle] = cb;
712 state.dcallbacks[handle] = dcb;
713 for(auto i : state.functions)
714 cb(i.first, i.second);
715 return handle;
718 void function_group::drop_callback(int handle)
720 threads::arlock h(get_lua_lock());
721 auto state = fgroup_internal_t::get_soft(this);
722 if(!state) return;
723 state->callbacks.erase(handle);
726 void function_group::do_register(const std::string& name, function& fun)
728 threads::arlock h(get_lua_lock());
729 auto& state = fgroup_internal_t::get(this);
730 if(state.functions.count(name)) return;
731 state.functions[name] = &fun;
732 for(auto i : state.callbacks)
733 i.second(name, &fun);
736 void function_group::do_unregister(const std::string& name, function& fun)
738 threads::arlock h(get_lua_lock());
739 auto state = fgroup_internal_t::get_soft(this);
740 if(!state || !state->functions.count(name) || state->functions[name] != &fun) return;
741 state->functions.erase(name);
742 for(auto i : state->callbacks)
743 i.second(name, NULL);
746 class_group::class_group()
750 class_group::~class_group()
752 threads::arlock h(get_lua_lock());
753 auto state = cgroup_internal_t::get_soft(this);
754 if(!state) return;
755 for(auto i : state->dcallbacks)
756 i.second(this);
757 cgroup_internal_t::clear(this);
760 void class_group::request_callback(std::function<void(std::string, class_base*)> cb)
762 threads::arlock h(get_lua_lock());
763 auto state = cgroup_internal_t::get_soft(this);
764 if(!state) return;
765 for(auto i : state->classes)
766 cb(i.first, i.second);
769 int class_group::add_callback(std::function<void(std::string, class_base*)> cb,
770 std::function<void(class_group*)> dcb)
772 threads::arlock h(get_lua_lock());
773 auto& state = cgroup_internal_t::get(this);
774 int handle = state.next_handle++;
775 state.callbacks[handle] = cb;
776 state.dcallbacks[handle] = dcb;
777 for(auto i : state.classes)
778 cb(i.first, i.second);
779 return handle;
782 void class_group::drop_callback(int handle)
784 threads::arlock h(get_lua_lock());
785 auto state = cgroup_internal_t::get_soft(this);
786 if(!state) return;
787 state->callbacks.erase(handle);
790 void class_group::do_register(const std::string& name, class_base& fun)
792 threads::arlock h(get_lua_lock());
793 auto& state = cgroup_internal_t::get(this);
794 if(state.classes.count(name)) return;
795 state.classes[name] = &fun;
796 for(auto i : state.callbacks)
797 i.second(name, &fun);
800 void class_group::do_unregister(const std::string& name, class_base& fun)
802 threads::arlock h(get_lua_lock());
803 auto state = cgroup_internal_t::get_soft(this);
804 if(!state || !state->classes.count(name) || state->classes[name] != &fun) return;
805 state->classes.erase(name);
806 for(auto i : state->callbacks)
807 i.second(name, NULL);
810 std::list<class_ops>& userdata_recogn_fns()
812 static std::list<class_ops> x;
813 return x;
816 std::string try_recognize_userdata(state& state, int index)
818 for(auto i : userdata_recogn_fns())
819 if(i.is(state, index))
820 return i.name();
821 //Hack: Lua builtin file objects and classobjs.
822 if(state.getmetatable(index)) {
823 state.pushstring("FILE*");
824 state.rawget(LUA_REGISTRYINDEX);
825 if(state.rawequal(-1, -2)) {
826 state.pop(2);
827 return "FILE*";
829 state.pop(1);
830 state.pushlightuserdata(&classtable_meta_key);
831 state.rawget(LUA_REGISTRYINDEX);
832 if(state.rawequal(-1, -2)) {
833 state.pop(2);
834 return "classobj";
836 state.pop(1);
838 return "unknown";
841 std::string try_print_userdata(state& L, int index)
843 for(auto i : userdata_recogn_fns())
844 if(i.is(L, index))
845 return i.print(L, index);
846 //Hack: classobjs.
847 if(L.getmetatable(index)) {
848 L.pushlightuserdata(&classtable_meta_key);
849 L.rawget(LUA_REGISTRYINDEX);
850 if(L.rawequal(-1, -2)) {
851 L.pop(2);
852 std::string cname = ((class_info*)L.touserdata(index))->obj->get_name();
853 return cname;
855 L.pop(1);
857 return "no data available";
860 int state::vararg_tag::pushargs(state& L)
862 int e = 0;
863 for(auto i : args) {
864 if(i == "")
865 L.pushnil();
866 else if(i == "true")
867 L.pushboolean(true);
868 else if(i == "false")
869 L.pushboolean(false);
870 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i))
871 L.pushnumber(strtod(i.c_str(), NULL));
872 else if(i[0] == ':')
873 L.pushlstring(i.substr(1));
874 else
875 L.pushlstring(i);
876 e++;
878 return e;
881 class_base* class_base::lookup(state& L, const std::string& _name)
883 if(lookup_and_push(L, _name)) {
884 class_base* obj = ((class_info*)L.touserdata(-1))->obj;
885 L.pop(1);
886 return obj;
888 return NULL;
891 bool class_base::lookup_and_push(state& L, const std::string& _name)
893 L.pushlightuserdata(&classtable_key);
894 L.rawget(LUA_REGISTRYINDEX);
895 if(L.type(-1) == LUA_TNIL) {
896 //No classes.
897 L.pop(1);
898 return false;
900 //On top of stack there is class table.
901 L.pushlstring(_name);
902 L.rawget(-2);
903 if(L.type(-1) == LUA_TNIL) {
904 //Not found.
905 L.pop(2);
906 return false;
908 L.insert(-2);
909 L.pop(1);
910 return true;
913 std::set<std::string> class_base::all_classes(state& L)
915 L.pushlightuserdata(&classtable_key);
916 L.rawget(LUA_REGISTRYINDEX);
917 if(L.type(-1) == LUA_TNIL) {
918 //No classes.
919 L.pop(1);
920 return std::set<std::string>();
922 std::set<std::string> r;
923 L.pushnil();
924 while(L.next(-2)) {
925 L.pop(1); //Pop value.
926 if(L.type(-1) == LUA_TSTRING) r.insert(L.tostring(-1));
928 L.pop(1);
929 return r;
932 void class_base::register_static(state& L)
934 again:
935 L.pushlightuserdata(&classtable_key);
936 L.rawget(LUA_REGISTRYINDEX);
937 if(L.type(-1) == LUA_TNIL) {
938 L.pop(1);
939 L.pushlightuserdata(&classtable_key);
940 L.newtable();
941 L.rawset(LUA_REGISTRYINDEX);
942 goto again;
944 //On top of stack there is class table.
945 L.pushlstring(name);
946 L.rawget(-2);
947 if(L.type(-1) != LUA_TNIL) {
948 //Already registered.
949 L.pop(2);
950 return;
952 L.pop(1);
953 L.pushlstring(name);
954 //Now construct the object.
955 class_info* ci = (class_info*)L.newuserdata(sizeof(class_info));
956 ci->obj = this;
957 again2:
958 L.pushlightuserdata(&classtable_meta_key);
959 L.rawget(LUA_REGISTRYINDEX);
960 if(L.type(-1) == LUA_TNIL) {
961 L.pop(1);
962 L.pushlightuserdata(&classtable_meta_key);
963 L.newtable();
964 L.pushstring("__index");
965 L.push_trampoline(class_info::index, 0);
966 L.rawset(-3);
967 L.pushstring("__newindex");
968 L.push_trampoline(class_info::newindex, 0);
969 L.rawset(-3);
970 L.pushstring("__pairs");
971 L.push_trampoline(class_info::pairs, 0);
972 L.rawset(-3);
973 L.rawset(LUA_REGISTRYINDEX);
974 goto again2;
976 L.setmetatable(-2);
977 L.rawset(-3);
978 L.pop(1);
981 void class_base::delayed_register()
983 group.do_register(name, *this);
986 functions::functions(function_group& grp, const std::string& basetable, std::initializer_list<entry> fnlist)
988 std::string base = (basetable == "") ? "" : (basetable + ".");
989 for(auto i : fnlist)
990 funcs.insert(new fn(grp, base + i.name, i.func));
993 functions::~functions()
995 for(auto i : funcs)
996 delete i;
999 functions::fn::fn(function_group& grp, const std::string& name, std::function<int(state& L, parameters& P)> _func)
1000 : function(grp, name)
1002 func = _func;
1005 functions::fn::~fn() throw()
1009 int functions::fn::invoke(state& L)
1011 lua::parameters P(L, fname);
1012 return func(L, P);