Small cleanup: move up some lsnes_instance stuff
[lsnes.git] / src / library / lua.cpp
blob418c6ab16aa91f6b303e54e6b0fd4eefd236d38e
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 <iostream>
9 #include <cassert>
11 namespace lua
13 namespace
15 threads::rlock* global_lock;
16 threads::rlock& get_lua_lock()
18 if(!global_lock) global_lock = new threads::rlock;
19 return *global_lock;
22 struct state_internal
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
31 fgroup_internal()
33 next_handle = 0;
35 std::map<std::string, function*> functions;
36 int next_handle;
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
43 cgroup_internal()
45 next_handle = 0;
47 int next_handle;
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;
61 return x;
63 namespace
65 char classtable_key;
66 char classtable_meta_key;
68 struct class_info
70 class_base* obj;
71 static int index(state& L);
72 static int newindex(state& L);
73 static int pairs(state& L);
74 static int pairs_next(state& L);
75 static int smethods(state& L);
76 static int cmethods(state& L);
77 static int trampoline(state& L);
78 static void check(state& L);
81 void class_info::check(state& L)
83 L.pushlightuserdata(&classtable_meta_key);
84 L.rawget(LUA_REGISTRYINDEX);
85 L.getmetatable(1);
86 if(!L.rawequal(-1, -2))
87 throw std::runtime_error("Bad class table");
88 L.pop(2);
91 int class_info::index(state& L)
93 check(L);
95 class_base* ptr = ((class_info*)L.touserdata(1))->obj;
96 const char* method = L.tostring(2);
97 if(!method)
98 throw std::runtime_error("Indexing invalid element of class table");
99 if(!strcmp(method, "_static_methods")) {
100 L.pushlightuserdata(ptr);
101 L.push_trampoline(class_info::smethods, 1);
102 return 1;
103 } else if(!strcmp(method, "_class_methods")) {
104 L.pushlightuserdata(ptr);
105 L.push_trampoline(class_info::cmethods, 1);
106 return 1;
107 } else {
108 auto m = ptr->static_methods();
109 for(auto i : m) {
110 if(!strcmp(i.name, method)) {
111 //Hit.
112 std::string fname = ptr->get_name() + "::" + i.name;
113 L.pushlightuserdata((void*)i.fn);
114 L.pushstring(fname.c_str());
115 L.push_trampoline(class_info::trampoline, 2);
116 return 1;
119 std::string err = std::string("Class '") + ptr->get_name() +
120 "' does not have static method '" + method + "'";
121 throw std::runtime_error(err);
123 return 0; //NOTREACHED
125 int class_info::newindex(state& L)
127 throw std::runtime_error("Writing into class table not allowed");
130 int class_info::pairs(state& L)
132 check(L);
134 L.push_trampoline(class_info::pairs_next, 0); //Next.
135 L.pushvalue(1); //State.
136 L.pushnil(); //Index.
137 return 3;
140 int class_info::pairs_next(state& L)
142 check(L);
144 class_base* obj = ((class_info*)L.touserdata(1))->obj;
145 auto m = obj->static_methods();
146 std::string key = (L.type(2) == LUA_TSTRING) ? L.tostring(2) : "";
147 std::string lowbound = "\xFF"; //Sorts greater than anything that is valid UTF-8.
148 void* best_fn = NULL;
149 for(auto i : m)
150 if(lowbound > i.name && i.name > key) {
151 lowbound = i.name;
152 best_fn = (void*)i.fn;
154 if(best_fn) {
155 L.pushlstring(lowbound);
156 std::string name = obj->get_name() + "::" + lowbound;
157 L.pushlightuserdata(best_fn);
158 L.pushlstring(name);
159 L.push_trampoline(class_info::trampoline, 2);
160 return 2;
161 } else {
162 L.pushnil();
163 return 1;
167 int class_info::smethods(state& L)
169 class_base* obj = (class_base*)L.touserdata(L.trampoline_upval(1));
170 auto m = obj->static_methods();
171 int rets = 0;
172 for(auto i : m) {
173 L.pushstring(i.name);
174 rets++;
176 return rets;
179 int class_info::cmethods(state& L)
181 class_base* obj = (class_base*)L.touserdata(L.trampoline_upval(1));
182 auto m = obj->class_methods();
183 int rets = 0;
184 for(auto i : m) {
185 L.pushstring(i.c_str());
186 rets++;
188 return rets;
191 typedef int (*fn_t)(state& L, parameters& P);
192 typedef int (*fnraw_t)(state& L);
194 //2 upvalues:
195 //1) Pointer to function control block.
196 //2) Pointer to method name.
197 int class_info::trampoline(state& L)
199 void* _fn = L.touserdata(L.trampoline_upval(1));
200 fn_t fn = (fn_t)_fn;
201 std::string name = L.tostring(L.trampoline_upval(2));
202 parameters P(L, name);
203 return fn(L, P);
206 //1 upvalue:
207 //1) Pointer to function control block.
208 int lua_trampoline_function(state& L)
210 void* ptr = L.touserdata(L.trampoline_upval(1));
211 function* f = reinterpret_cast<function*>(ptr);
212 return f->invoke(L);
215 //2 upvalues.
216 //1) Pointer to master state.
217 //2) Poiinter to function to call.
218 int lua_main_trampoline(lua_State* L)
220 state* lstate = reinterpret_cast<state*>(lua_touserdata(L, lua_upvalueindex(1)));
221 void* _fn = lua_touserdata(L, lua_upvalueindex(2));
222 fnraw_t fn = (fnraw_t)_fn;
223 //The function is always run in non-set_interruptable mode.
224 try {
225 state _L(*lstate, L);
226 lstate->set_interruptable_flag(false);
227 int r = fn(_L);
228 lstate->set_interruptable_flag(true);
229 return r;
230 } catch(std::exception& e) {
231 lua_pushfstring(L, "%s", e.what());
232 lstate->set_interruptable_flag(true);
233 lua_error(L);
235 return 0;
238 //Pushes given table to top of stack, creating if needed.
239 void recursive_lookup_table(state& L, const std::string& tab)
241 if(tab == "") {
242 L.pushglobals();
243 assert(L.type(-1) == LUA_TTABLE);
244 return;
246 std::string u = tab;
247 size_t split = u.find_last_of(".");
248 std::string u1;
249 std::string u2 = u;
250 if(split < u.length()) {
251 u1 = u.substr(0, split);
252 u2 = u.substr(split + 1);
254 recursive_lookup_table(L, u1);
255 L.getfield(-1, u2.c_str());
256 if(L.type(-1) != LUA_TTABLE) {
257 //Not a table, create a table.
258 L.pop(1);
259 L.newtable();
260 L.setfield(-2, u2.c_str());
261 L.getfield(-1, u2.c_str());
263 //Get rid of previous table.
264 L.insert(-2);
265 L.pop(1);
268 void register_function(state& L, const std::string& name, function* fun)
270 std::string u = name;
271 size_t split = u.find_last_of(".");
272 std::string u1;
273 std::string u2 = u;
274 if(split < u.length()) {
275 u1 = u.substr(0, split);
276 u2 = u.substr(split + 1);
278 recursive_lookup_table(L, u1);
279 if(!fun)
280 L.pushnil();
281 else {
282 void* ptr = reinterpret_cast<void*>(fun);
283 L.pushlightuserdata(ptr);
284 L.push_trampoline(lua_trampoline_function, 1);
286 L.setfield(-2, u2.c_str());
287 L.pop(1);
290 void register_class(state& L, const std::string& name, class_base* fun)
292 fun->register_state(L);
295 int run_interruptable_trampoline(lua_State* L)
297 //Be very careful with faults here! We are running in interruptable context.
298 static std::string err;
299 auto& fn = *(std::function<void()>*)lua_touserdata(L, -1);
300 int out = lua_tonumber(L, -2);
301 lua_pop(L, 2); //fn is passed as a pointer, so popping it is OK.
302 try {
303 fn();
304 } catch(std::exception& e) {
305 err = e.what();
306 //This can fault, so err is static.
307 lua_pushlstring(L, err.c_str(), err.length());
308 lua_error(L);
310 return out;
314 state::state() throw(std::bad_alloc)
316 master = NULL;
317 lua_handle = NULL;
318 oom_handler = builtin_oom;
319 soft_oom_handler = builtin_soft_oom;
320 interruptable = false; //Assume initially not interruptable.
321 memory_limit = (size_t)-1; //Unlimited.
322 memory_use = 0;
325 state::state(state& _master, lua_State* L)
327 master = &_master;
328 lua_handle = L;
331 state::~state() throw()
333 if(master)
334 return;
335 threads::arlock h(get_lua_lock());
336 auto state = state_internal_t::get_soft(this);
337 if(!state) return;
338 for(auto i : state->function_groups)
339 i.first->drop_callback(i.second);
340 for(auto i : state->class_groups)
341 i.first->drop_callback(i.second);
342 if(lua_handle)
343 lua_close(lua_handle);
344 state_internal_t::clear(this);
347 void state::builtin_oom()
349 std::cerr << "PANIC: FATAL: Out of memory" << std::endl;
350 exit(1);
353 void state::builtin_soft_oom(int status)
355 if(status == 0)
356 std::cerr << "Lua: Memory limit exceeded, attempting to free memory..." << std::endl;
357 if(status < 0)
358 std::cerr << "Lua: Memory allocation still failed." << std::endl;
359 if(status > 0)
360 std::cerr << "Lua: Allocation successful after freeing some memory." << std::endl;
363 void* state::builtin_alloc(void* user, void* old, size_t olds, size_t news)
365 void* m;
366 auto& st = *reinterpret_cast<state*>(user);
367 if(news) {
368 if(news > olds && !st.charge_memory(news - olds, false)) {
369 goto retry_allocation;
371 m = realloc(old, news);
372 if(!m && !st.get_interruptable_flag())
373 st.oom_handler();
374 if(!m) {
375 st.charge_memory(news - olds, true); //Undo commit.
376 goto retry_allocation;
378 if(news < olds)
379 st.charge_memory(olds - news, true); //Release memory.
380 if(m && st.memory_change) st.memory_change((ssize_t)news - (ssize_t)olds);
381 return m;
382 } else {
383 st.charge_memory(olds, true); //Release memory.
384 if(st.memory_change) st.memory_change(-(ssize_t)olds);
385 free(old);
387 return NULL;
388 retry_allocation:
389 st.soft_oom_handler(0);
390 st.interruptable = false; //Give everything we got for the GC.
391 lua_gc(st.lua_handle, LUA_GCCOLLECT,0); //Do full cycle to try to free some memory.
392 st.interruptable = true;
393 if(!st.charge_memory(news - olds, false)) { //Try to see if memory can be allocated.
394 st.soft_oom_handler(-1);
395 return NULL;
397 m = realloc(old, news);
398 if(!m && news > olds)
399 st.charge_memory(news - olds, true); //Undo commit.
400 st.soft_oom_handler(m ? 1 : -1);
401 if(m && st.memory_change) st.memory_change((ssize_t)news - (ssize_t)olds);
402 return m;
405 void state::push_trampoline(int(*fn)(state& L), unsigned n_upvals)
407 lua_pushlightuserdata(lua_handle, (void*)&get_master());
408 lua_pushlightuserdata(lua_handle, (void*)fn);
409 if(n_upvals > 0) {
410 lua_insert(lua_handle, -(int)n_upvals - 2);
411 lua_insert(lua_handle, -(int)n_upvals - 2);
413 lua_pushcclosure(lua_handle, lua_main_trampoline, trampoline_upvals + n_upvals);
416 //Lua 5.1 doesn't define LUA_OK.
417 #ifndef LUA_OK
418 #define LUA_OK 0
419 #endif
421 void state::run_interruptable(std::function<void()> fn, unsigned in, unsigned out)
423 pushnumber(out);
424 pushlightuserdata(&fn);
425 pushcfunction(run_interruptable_trampoline);
426 insert(-(int)in - 3);
427 int r = pcall(in + 2, out, 0);
428 if(r == LUA_OK) {
429 //Nothing.
430 } else if(r == LUA_ERRRUN) {
431 throw std::runtime_error(tostring(-1));
432 } else if(r == LUA_ERRMEM) {
433 throw std::runtime_error("Lua out of memory");
434 } else if(r == LUA_ERRERR) {
435 throw std::runtime_error("Lua double fault");
436 #ifdef LUA_ERRGCMM
437 } else if(r == LUA_ERRGCMM) {
438 throw std::runtime_error("Lua fault in garbage collector");
439 #endif
443 bool state::charge_memory(size_t amount, bool release)
445 if(master) return master->charge_memory(amount, release);
446 if(release) {
447 if(memory_use > amount)
448 memory_use -= amount;
449 else
450 memory_use = 0;
451 return true;
453 if(!interruptable) {
454 //Give everything we got.
455 memory_use += amount;
456 return true;
457 } else {
458 //Check limit and refuse allocations too large.
459 if(memory_use + amount > memory_limit || memory_use + amount < amount)
460 return false;
461 memory_use += amount;
462 return true;
466 function::function(function_group& _group, const std::string& func) throw(std::bad_alloc)
467 : group(_group)
469 group.do_register(fname = func, *this);
472 function::~function() throw()
474 group.do_unregister(fname, *this);
477 class_base::class_base(class_group& _group, const std::string& _name)
478 : group(_group), name(_name)
480 registered = false;
483 class_base::~class_base() throw()
485 if(registered)
486 group.do_unregister(name, *this);
489 void state::reset() throw(std::bad_alloc, std::runtime_error)
491 if(master)
492 return master->reset();
493 threads::arlock h(get_lua_lock());
494 auto state = &state_internal_t::get(this);
495 if(lua_handle) {
496 lua_State* tmp = lua_newstate(state::builtin_alloc, this);
497 if(!tmp)
498 throw std::runtime_error("Can't re-initialize Lua interpretter");
499 lua_close(lua_handle);
500 for(auto& i : state->callbacks)
501 i.second->clear();
502 lua_handle = tmp;
503 } else {
504 //Initialize new.
505 lua_handle = lua_newstate(state::builtin_alloc, this);
506 if(!lua_handle)
507 throw std::runtime_error("Can't initialize Lua interpretter");
509 for(auto i : state->function_groups)
510 i.first->request_callback([this](std::string name, function* func) -> void {
511 register_function(*this, name, func);
513 for(auto i : state->class_groups)
514 i.first->request_callback([this](std::string name, class_base* clazz) -> void {
515 register_class(*this, name, clazz);
519 void state::deinit() throw()
521 if(master)
522 return master->deinit();
523 if(lua_handle)
524 lua_close(lua_handle);
525 lua_handle = NULL;
528 void state::add_function_group(function_group& group)
530 threads::arlock h(get_lua_lock());
531 auto& state = state_internal_t::get(this);
532 state.function_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
533 function* func) -> void {
534 this->function_callback(name, func);
535 }, [this](function_group* x) {
536 threads::arlock h(get_lua_lock());
537 auto state = state_internal_t::get_soft(this);
538 if(!state) return;
539 for(auto i = state->function_groups.begin(); i != state->function_groups.end();)
540 if(i->first == x)
541 i = state->function_groups.erase(i);
542 else
543 i++;
544 })));
547 void state::add_class_group(class_group& group)
549 threads::arlock h(get_lua_lock());
550 auto& state = state_internal_t::get(this);
551 state.class_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
552 class_base* clazz) -> void {
553 this->class_callback(name, clazz);
554 }, [this](class_group* x) {
555 threads::arlock h(get_lua_lock());
556 auto state = state_internal_t::get_soft(this);
557 if(!state) return;
558 for(auto i = state->class_groups.begin(); i != state->class_groups.end();)
559 if(i->first == x)
560 i = state->class_groups.erase(i);
561 else
562 i++;
563 })));
566 void state::function_callback(const std::string& name, function* func)
568 if(master)
569 return master->function_callback(name, func);
570 if(lua_handle)
571 register_function(*this, name, func);
574 void state::class_callback(const std::string& name, class_base* clazz)
576 if(master)
577 return master->class_callback(name, clazz);
578 if(lua_handle)
579 register_class(*this, name, clazz);
582 bool state::do_once(void* key)
584 if(master)
585 return master->do_once(key);
586 pushlightuserdata(key);
587 rawget(LUA_REGISTRYINDEX);
588 if(type(-1) == LUA_TNIL) {
589 pop(1);
590 pushlightuserdata(key);
591 pushlightuserdata(key);
592 rawset(LUA_REGISTRYINDEX);
593 return true;
594 } else {
595 pop(1);
596 return false;
600 std::list<state::callback_list*> state::get_callbacks()
602 if(master)
603 return master->get_callbacks();
604 threads::arlock h(get_lua_lock());
605 auto state = state_internal_t::get_soft(this);
606 std::list<callback_list*> r;
607 if(state)
608 for(auto i : state->callbacks)
609 r.push_back(i.second);
610 return r;
613 void state::do_register(const std::string& name, callback_list& callback)
615 threads::arlock h(get_lua_lock());
616 auto& state = state_internal_t::get(this);
617 if(state.callbacks.count(name)) return;
618 state.callbacks[name] = &callback;
621 void state::do_unregister(const std::string& name, callback_list& callback)
623 threads::arlock h(get_lua_lock());
624 auto state = state_internal_t::get_soft(this);
625 if(state && state->callbacks.count(name) && state->callbacks[name] == &callback)
626 state->callbacks.erase(name);
629 state::callback_list::callback_list(state& _L, const std::string& _name, const std::string& fncbname)
630 : L(_L), name(_name), fn_cbname(fncbname)
632 L.do_register(name, *this);
635 state::callback_list::~callback_list()
637 L.do_unregister(name, *this);
638 if(!L.handle())
639 return;
640 for(auto& i : callbacks) {
641 L.pushlightuserdata(&i);
642 L.pushnil();
643 L.rawset(LUA_REGISTRYINDEX);
647 void state::callback_list::_register(state& _L)
649 callbacks.push_back(0);
650 _L.pushlightuserdata(&*callbacks.rbegin());
651 _L.pushvalue(-2);
652 _L.rawset(LUA_REGISTRYINDEX);
655 void state::callback_list::_unregister(state& _L)
657 for(auto i = callbacks.begin(); i != callbacks.end();) {
658 _L.pushlightuserdata(&*i);
659 _L.rawget(LUA_REGISTRYINDEX);
660 if(_L.rawequal(-1, -2)) {
661 char* key = &*i;
662 _L.pushlightuserdata(key);
663 _L.pushnil();
664 _L.rawset(LUA_REGISTRYINDEX);
665 i = callbacks.erase(i);
666 } else
667 i++;
668 _L.pop(1);
672 function_group::function_group()
676 function_group::~function_group()
678 threads::arlock h(get_lua_lock());
679 auto state = fgroup_internal_t::get_soft(this);
680 if(!state) return;
681 for(auto i : state->dcallbacks)
682 i.second(this);
683 fgroup_internal_t::clear(this);
686 void function_group::request_callback(std::function<void(std::string, function*)> cb)
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->functions)
692 cb(i.first, i.second);
695 int function_group::add_callback(std::function<void(std::string, function*)> cb,
696 std::function<void(function_group*)> dcb)
698 threads::arlock h(get_lua_lock());
699 auto& state = fgroup_internal_t::get(this);
700 int handle = state.next_handle++;
701 state.callbacks[handle] = cb;
702 state.dcallbacks[handle] = dcb;
703 for(auto i : state.functions)
704 cb(i.first, i.second);
705 return handle;
708 void function_group::drop_callback(int handle)
710 threads::arlock h(get_lua_lock());
711 auto state = fgroup_internal_t::get_soft(this);
712 if(!state) return;
713 state->callbacks.erase(handle);
716 void function_group::do_register(const std::string& name, function& fun)
718 threads::arlock h(get_lua_lock());
719 auto& state = fgroup_internal_t::get(this);
720 if(state.functions.count(name)) return;
721 state.functions[name] = &fun;
722 for(auto i : state.callbacks)
723 i.second(name, &fun);
726 void function_group::do_unregister(const std::string& name, function& fun)
728 threads::arlock h(get_lua_lock());
729 auto state = fgroup_internal_t::get_soft(this);
730 if(!state || !state->functions.count(name) || state->functions[name] != &fun) return;
731 state->functions.erase(name);
732 for(auto i : state->callbacks)
733 i.second(name, NULL);
736 class_group::class_group()
740 class_group::~class_group()
742 threads::arlock h(get_lua_lock());
743 auto state = cgroup_internal_t::get_soft(this);
744 if(!state) return;
745 for(auto i : state->dcallbacks)
746 i.second(this);
747 cgroup_internal_t::clear(this);
750 void class_group::request_callback(std::function<void(std::string, class_base*)> cb)
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->classes)
756 cb(i.first, i.second);
759 int class_group::add_callback(std::function<void(std::string, class_base*)> cb,
760 std::function<void(class_group*)> dcb)
762 threads::arlock h(get_lua_lock());
763 auto& state = cgroup_internal_t::get(this);
764 int handle = state.next_handle++;
765 state.callbacks[handle] = cb;
766 state.dcallbacks[handle] = dcb;
767 for(auto i : state.classes)
768 cb(i.first, i.second);
769 return handle;
772 void class_group::drop_callback(int handle)
774 threads::arlock h(get_lua_lock());
775 auto state = cgroup_internal_t::get_soft(this);
776 if(!state) return;
777 state->callbacks.erase(handle);
780 void class_group::do_register(const std::string& name, class_base& fun)
782 threads::arlock h(get_lua_lock());
783 auto& state = cgroup_internal_t::get(this);
784 if(state.classes.count(name)) return;
785 state.classes[name] = &fun;
786 for(auto i : state.callbacks)
787 i.second(name, &fun);
790 void class_group::do_unregister(const std::string& name, class_base& fun)
792 threads::arlock h(get_lua_lock());
793 auto state = cgroup_internal_t::get_soft(this);
794 if(!state || !state->classes.count(name) || state->classes[name] != &fun) return;
795 state->classes.erase(name);
796 for(auto i : state->callbacks)
797 i.second(name, NULL);
800 std::list<class_ops>& userdata_recogn_fns()
802 static std::list<class_ops> x;
803 return x;
806 std::string try_recognize_userdata(state& state, int index)
808 for(auto i : userdata_recogn_fns())
809 if(i.is(state, index))
810 return i.name();
811 //Hack: Lua builtin file objects and classobjs.
812 if(state.getmetatable(index)) {
813 state.pushstring("FILE*");
814 state.rawget(LUA_REGISTRYINDEX);
815 if(state.rawequal(-1, -2)) {
816 state.pop(2);
817 return "FILE*";
819 state.pop(1);
820 state.pushlightuserdata(&classtable_meta_key);
821 state.rawget(LUA_REGISTRYINDEX);
822 if(state.rawequal(-1, -2)) {
823 state.pop(2);
824 return "classobj";
826 state.pop(1);
828 return "unknown";
831 std::string try_print_userdata(state& L, int index)
833 for(auto i : userdata_recogn_fns())
834 if(i.is(L, index))
835 return i.print(L, index);
836 //Hack: classobjs.
837 if(L.getmetatable(index)) {
838 L.pushlightuserdata(&classtable_meta_key);
839 L.rawget(LUA_REGISTRYINDEX);
840 if(L.rawequal(-1, -2)) {
841 L.pop(2);
842 std::string cname = ((class_info*)L.touserdata(index))->obj->get_name();
843 return cname;
845 L.pop(1);
847 return "no data available";
850 int state::vararg_tag::pushargs(state& L)
852 int e = 0;
853 for(auto i : args) {
854 if(i == "")
855 L.pushnil();
856 else if(i == "true")
857 L.pushboolean(true);
858 else if(i == "false")
859 L.pushboolean(false);
860 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i))
861 L.pushnumber(strtod(i.c_str(), NULL));
862 else if(i[0] == ':')
863 L.pushlstring(i.substr(1));
864 else
865 L.pushlstring(i);
866 e++;
868 return e;
871 class_base* class_base::lookup(state& L, const std::string& _name)
873 if(lookup_and_push(L, _name)) {
874 class_base* obj = ((class_info*)L.touserdata(-1))->obj;
875 L.pop(1);
876 return obj;
878 return NULL;
881 bool class_base::lookup_and_push(state& L, const std::string& _name)
883 L.pushlightuserdata(&classtable_key);
884 L.rawget(LUA_REGISTRYINDEX);
885 if(L.type(-1) == LUA_TNIL) {
886 //No classes.
887 L.pop(1);
888 return false;
890 //On top of stack there is class table.
891 L.pushlstring(_name);
892 L.rawget(-2);
893 if(L.type(-1) == LUA_TNIL) {
894 //Not found.
895 L.pop(2);
896 return false;
898 L.insert(-2);
899 L.pop(1);
900 return true;
903 std::set<std::string> class_base::all_classes(state& L)
905 L.pushlightuserdata(&classtable_key);
906 L.rawget(LUA_REGISTRYINDEX);
907 if(L.type(-1) == LUA_TNIL) {
908 //No classes.
909 L.pop(1);
910 return std::set<std::string>();
912 std::set<std::string> r;
913 L.pushnil();
914 while(L.next(-2)) {
915 L.pop(1); //Pop value.
916 if(L.type(-1) == LUA_TSTRING) r.insert(L.tostring(-1));
918 L.pop(1);
919 return r;
922 void class_base::register_static(state& L)
924 again:
925 L.pushlightuserdata(&classtable_key);
926 L.rawget(LUA_REGISTRYINDEX);
927 if(L.type(-1) == LUA_TNIL) {
928 L.pop(1);
929 L.pushlightuserdata(&classtable_key);
930 L.newtable();
931 L.rawset(LUA_REGISTRYINDEX);
932 goto again;
934 //On top of stack there is class table.
935 L.pushlstring(name);
936 L.rawget(-2);
937 if(L.type(-1) != LUA_TNIL) {
938 //Already registered.
939 L.pop(2);
940 return;
942 L.pop(1);
943 L.pushlstring(name);
944 //Now construct the object.
945 class_info* ci = (class_info*)L.newuserdata(sizeof(class_info));
946 ci->obj = this;
947 again2:
948 L.pushlightuserdata(&classtable_meta_key);
949 L.rawget(LUA_REGISTRYINDEX);
950 if(L.type(-1) == LUA_TNIL) {
951 L.pop(1);
952 L.pushlightuserdata(&classtable_meta_key);
953 L.newtable();
954 L.pushstring("__index");
955 L.push_trampoline(class_info::index, 0);
956 L.rawset(-3);
957 L.pushstring("__newindex");
958 L.push_trampoline(class_info::newindex, 0);
959 L.rawset(-3);
960 L.pushstring("__pairs");
961 L.push_trampoline(class_info::pairs, 0);
962 L.rawset(-3);
963 L.rawset(LUA_REGISTRYINDEX);
964 goto again2;
966 L.setmetatable(-2);
967 L.rawset(-3);
968 L.pop(1);
971 void class_base::delayed_register()
973 group.do_register(name, *this);
976 functions::functions(function_group& grp, const std::string& basetable, std::initializer_list<entry> fnlist)
978 std::string base = (basetable == "") ? "" : (basetable + ".");
979 for(auto i : fnlist)
980 funcs.insert(new fn(grp, base + i.name, i.func));
983 functions::~functions()
985 for(auto i : funcs)
986 delete i;
989 functions::fn::fn(function_group& grp, const std::string& name, std::function<int(state& L, parameters& P)> _func)
990 : function(grp, name)
992 func = _func;
995 functions::fn::~fn() throw()
999 int functions::fn::invoke(state& L)
1001 lua::parameters P(L, fname);
1002 return func(L, P);