lsnes rr2-β24
[lsnes.git] / src / library / lua.cpp
blob8c6457ca0ba6575a615c517d6b0be999ea798aad
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() throw(std::bad_alloc)
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) throw(std::bad_alloc)
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() throw(std::bad_alloc, std::runtime_error)
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 L.do_register(name, *this);
636 state::callback_list::~callback_list()
638 L.do_unregister(name, *this);
639 if(!L.handle())
640 return;
641 for(auto& i : callbacks) {
642 L.pushlightuserdata(&i);
643 L.pushnil();
644 L.rawset(LUA_REGISTRYINDEX);
648 void state::callback_list::_register(state& _L)
650 callbacks.push_back(0);
651 _L.pushlightuserdata(&*callbacks.rbegin());
652 _L.pushvalue(-2);
653 _L.rawset(LUA_REGISTRYINDEX);
656 void state::callback_list::_unregister(state& _L)
658 for(auto i = callbacks.begin(); i != callbacks.end();) {
659 _L.pushlightuserdata(&*i);
660 _L.rawget(LUA_REGISTRYINDEX);
661 if(_L.rawequal(-1, -2)) {
662 char* key = &*i;
663 _L.pushlightuserdata(key);
664 _L.pushnil();
665 _L.rawset(LUA_REGISTRYINDEX);
666 i = callbacks.erase(i);
667 } else
668 i++;
669 _L.pop(1);
673 function_group::function_group()
677 function_group::~function_group()
679 threads::arlock h(get_lua_lock());
680 auto state = fgroup_internal_t::get_soft(this);
681 if(!state) return;
682 for(auto i : state->dcallbacks)
683 i.second(this);
684 fgroup_internal_t::clear(this);
687 void function_group::request_callback(std::function<void(std::string, function*)> cb)
689 threads::arlock h(get_lua_lock());
690 auto state = fgroup_internal_t::get_soft(this);
691 if(!state) return;
692 for(auto i : state->functions)
693 cb(i.first, i.second);
696 int function_group::add_callback(std::function<void(std::string, function*)> cb,
697 std::function<void(function_group*)> dcb)
699 threads::arlock h(get_lua_lock());
700 auto& state = fgroup_internal_t::get(this);
701 int handle = state.next_handle++;
702 state.callbacks[handle] = cb;
703 state.dcallbacks[handle] = dcb;
704 for(auto i : state.functions)
705 cb(i.first, i.second);
706 return handle;
709 void function_group::drop_callback(int handle)
711 threads::arlock h(get_lua_lock());
712 auto state = fgroup_internal_t::get_soft(this);
713 if(!state) return;
714 state->callbacks.erase(handle);
717 void function_group::do_register(const std::string& name, function& fun)
719 threads::arlock h(get_lua_lock());
720 auto& state = fgroup_internal_t::get(this);
721 if(state.functions.count(name)) return;
722 state.functions[name] = &fun;
723 for(auto i : state.callbacks)
724 i.second(name, &fun);
727 void function_group::do_unregister(const std::string& name, function& fun)
729 threads::arlock h(get_lua_lock());
730 auto state = fgroup_internal_t::get_soft(this);
731 if(!state || !state->functions.count(name) || state->functions[name] != &fun) return;
732 state->functions.erase(name);
733 for(auto i : state->callbacks)
734 i.second(name, NULL);
737 class_group::class_group()
741 class_group::~class_group()
743 threads::arlock h(get_lua_lock());
744 auto state = cgroup_internal_t::get_soft(this);
745 if(!state) return;
746 for(auto i : state->dcallbacks)
747 i.second(this);
748 cgroup_internal_t::clear(this);
751 void class_group::request_callback(std::function<void(std::string, class_base*)> cb)
753 threads::arlock h(get_lua_lock());
754 auto state = cgroup_internal_t::get_soft(this);
755 if(!state) return;
756 for(auto i : state->classes)
757 cb(i.first, i.second);
760 int class_group::add_callback(std::function<void(std::string, class_base*)> cb,
761 std::function<void(class_group*)> dcb)
763 threads::arlock h(get_lua_lock());
764 auto& state = cgroup_internal_t::get(this);
765 int handle = state.next_handle++;
766 state.callbacks[handle] = cb;
767 state.dcallbacks[handle] = dcb;
768 for(auto i : state.classes)
769 cb(i.first, i.second);
770 return handle;
773 void class_group::drop_callback(int handle)
775 threads::arlock h(get_lua_lock());
776 auto state = cgroup_internal_t::get_soft(this);
777 if(!state) return;
778 state->callbacks.erase(handle);
781 void class_group::do_register(const std::string& name, class_base& fun)
783 threads::arlock h(get_lua_lock());
784 auto& state = cgroup_internal_t::get(this);
785 if(state.classes.count(name)) return;
786 state.classes[name] = &fun;
787 for(auto i : state.callbacks)
788 i.second(name, &fun);
791 void class_group::do_unregister(const std::string& name, class_base& fun)
793 threads::arlock h(get_lua_lock());
794 auto state = cgroup_internal_t::get_soft(this);
795 if(!state || !state->classes.count(name) || state->classes[name] != &fun) return;
796 state->classes.erase(name);
797 for(auto i : state->callbacks)
798 i.second(name, NULL);
801 std::list<class_ops>& userdata_recogn_fns()
803 static std::list<class_ops> x;
804 return x;
807 std::string try_recognize_userdata(state& state, int index)
809 for(auto i : userdata_recogn_fns())
810 if(i.is(state, index))
811 return i.name();
812 //Hack: Lua builtin file objects and classobjs.
813 if(state.getmetatable(index)) {
814 state.pushstring("FILE*");
815 state.rawget(LUA_REGISTRYINDEX);
816 if(state.rawequal(-1, -2)) {
817 state.pop(2);
818 return "FILE*";
820 state.pop(1);
821 state.pushlightuserdata(&classtable_meta_key);
822 state.rawget(LUA_REGISTRYINDEX);
823 if(state.rawequal(-1, -2)) {
824 state.pop(2);
825 return "classobj";
827 state.pop(1);
829 return "unknown";
832 std::string try_print_userdata(state& L, int index)
834 for(auto i : userdata_recogn_fns())
835 if(i.is(L, index))
836 return i.print(L, index);
837 //Hack: classobjs.
838 if(L.getmetatable(index)) {
839 L.pushlightuserdata(&classtable_meta_key);
840 L.rawget(LUA_REGISTRYINDEX);
841 if(L.rawequal(-1, -2)) {
842 L.pop(2);
843 std::string cname = ((class_info*)L.touserdata(index))->obj->get_name();
844 return cname;
846 L.pop(1);
848 return "no data available";
851 int state::vararg_tag::pushargs(state& L)
853 int e = 0;
854 for(auto i : args) {
855 if(i == "")
856 L.pushnil();
857 else if(i == "true")
858 L.pushboolean(true);
859 else if(i == "false")
860 L.pushboolean(false);
861 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i))
862 L.pushnumber(strtod(i.c_str(), NULL));
863 else if(i[0] == ':')
864 L.pushlstring(i.substr(1));
865 else
866 L.pushlstring(i);
867 e++;
869 return e;
872 class_base* class_base::lookup(state& L, const std::string& _name)
874 if(lookup_and_push(L, _name)) {
875 class_base* obj = ((class_info*)L.touserdata(-1))->obj;
876 L.pop(1);
877 return obj;
879 return NULL;
882 bool class_base::lookup_and_push(state& L, const std::string& _name)
884 L.pushlightuserdata(&classtable_key);
885 L.rawget(LUA_REGISTRYINDEX);
886 if(L.type(-1) == LUA_TNIL) {
887 //No classes.
888 L.pop(1);
889 return false;
891 //On top of stack there is class table.
892 L.pushlstring(_name);
893 L.rawget(-2);
894 if(L.type(-1) == LUA_TNIL) {
895 //Not found.
896 L.pop(2);
897 return false;
899 L.insert(-2);
900 L.pop(1);
901 return true;
904 std::set<std::string> class_base::all_classes(state& L)
906 L.pushlightuserdata(&classtable_key);
907 L.rawget(LUA_REGISTRYINDEX);
908 if(L.type(-1) == LUA_TNIL) {
909 //No classes.
910 L.pop(1);
911 return std::set<std::string>();
913 std::set<std::string> r;
914 L.pushnil();
915 while(L.next(-2)) {
916 L.pop(1); //Pop value.
917 if(L.type(-1) == LUA_TSTRING) r.insert(L.tostring(-1));
919 L.pop(1);
920 return r;
923 void class_base::register_static(state& L)
925 again:
926 L.pushlightuserdata(&classtable_key);
927 L.rawget(LUA_REGISTRYINDEX);
928 if(L.type(-1) == LUA_TNIL) {
929 L.pop(1);
930 L.pushlightuserdata(&classtable_key);
931 L.newtable();
932 L.rawset(LUA_REGISTRYINDEX);
933 goto again;
935 //On top of stack there is class table.
936 L.pushlstring(name);
937 L.rawget(-2);
938 if(L.type(-1) != LUA_TNIL) {
939 //Already registered.
940 L.pop(2);
941 return;
943 L.pop(1);
944 L.pushlstring(name);
945 //Now construct the object.
946 class_info* ci = (class_info*)L.newuserdata(sizeof(class_info));
947 ci->obj = this;
948 again2:
949 L.pushlightuserdata(&classtable_meta_key);
950 L.rawget(LUA_REGISTRYINDEX);
951 if(L.type(-1) == LUA_TNIL) {
952 L.pop(1);
953 L.pushlightuserdata(&classtable_meta_key);
954 L.newtable();
955 L.pushstring("__index");
956 L.push_trampoline(class_info::index, 0);
957 L.rawset(-3);
958 L.pushstring("__newindex");
959 L.push_trampoline(class_info::newindex, 0);
960 L.rawset(-3);
961 L.pushstring("__pairs");
962 L.push_trampoline(class_info::pairs, 0);
963 L.rawset(-3);
964 L.rawset(LUA_REGISTRYINDEX);
965 goto again2;
967 L.setmetatable(-2);
968 L.rawset(-3);
969 L.pop(1);
972 void class_base::delayed_register()
974 group.do_register(name, *this);
977 functions::functions(function_group& grp, const std::string& basetable, std::initializer_list<entry> fnlist)
979 std::string base = (basetable == "") ? "" : (basetable + ".");
980 for(auto i : fnlist)
981 funcs.insert(new fn(grp, base + i.name, i.func));
984 functions::~functions()
986 for(auto i : funcs)
987 delete i;
990 functions::fn::fn(function_group& grp, const std::string& name, std::function<int(state& L, parameters& P)> _func)
991 : function(grp, name)
993 func = _func;
996 functions::fn::~fn() throw()
1000 int functions::fn::invoke(state& L)
1002 lua::parameters P(L, fname);
1003 return func(L, P);