Lua: Memory usage limit
[lsnes.git] / src / library / lua.cpp
blob135a8cd6a701b6032197a135b6909fbb16d2c47f
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 return m;
381 } else {
382 st.charge_memory(olds, true); //Release memory.
383 free(old);
385 return NULL;
386 retry_allocation:
387 st.soft_oom_handler(0);
388 st.interruptable = false; //Give everything we got for the GC.
389 lua_gc(st.lua_handle, LUA_GCCOLLECT,0); //Do full cycle to try to free some memory.
390 st.interruptable = true;
391 if(!st.charge_memory(news - olds, false)) { //Try to see if memory can be allocated.
392 st.soft_oom_handler(-1);
393 return NULL;
395 m = realloc(old, news);
396 if(!m && news > olds)
397 st.charge_memory(news - olds, true); //Undo commit.
398 st.soft_oom_handler(m ? 1 : -1);
399 return m;
403 void state::push_trampoline(int(*fn)(state& L), unsigned n_upvals)
405 lua_pushlightuserdata(lua_handle, (void*)&get_master());
406 lua_pushlightuserdata(lua_handle, (void*)fn);
407 if(n_upvals > 0) {
408 lua_insert(lua_handle, -(int)n_upvals - 2);
409 lua_insert(lua_handle, -(int)n_upvals - 2);
411 lua_pushcclosure(lua_handle, lua_main_trampoline, trampoline_upvals + n_upvals);
414 void state::run_interruptable(std::function<void()> fn, unsigned in, unsigned out)
416 pushnumber(out);
417 pushlightuserdata(&fn);
418 pushcfunction(run_interruptable_trampoline);
419 insert(-(int)in - 3);
420 int r = pcall(in + 2, out, 0);
421 if(r == LUA_OK) {
422 //Nothing.
423 } else if(r == LUA_ERRRUN) {
424 throw std::runtime_error(tostring(-1));
425 } else if(r == LUA_ERRMEM) {
426 throw std::runtime_error("Lua out of memory");
427 } else if(r == LUA_ERRERR) {
428 throw std::runtime_error("Lua double fault");
429 #ifdef LUA_ERRGCMM
430 } else if(r == LUA_ERRGCMM) {
431 throw std::runtime_error("Lua fault in garbage collector");
432 #endif
436 bool state::charge_memory(size_t amount, bool release)
438 if(master) return master->charge_memory(amount, release);
439 if(release) {
440 if(memory_use > amount)
441 memory_use -= amount;
442 else
443 memory_use = 0;
444 return true;
446 if(!interruptable) {
447 //Give everything we got.
448 memory_use += amount;
449 return true;
450 } else {
451 //Check limit and refuse allocations too large.
452 if(memory_use + amount > memory_limit || memory_use + amount < amount)
453 return false;
454 memory_use += amount;
455 return true;
459 function::function(function_group& _group, const std::string& func) throw(std::bad_alloc)
460 : group(_group)
462 group.do_register(fname = func, *this);
465 function::~function() throw()
467 group.do_unregister(fname, *this);
470 class_base::class_base(class_group& _group, const std::string& _name)
471 : group(_group), name(_name)
473 registered = false;
476 class_base::~class_base() throw()
478 if(registered)
479 group.do_unregister(name, *this);
482 void state::reset() throw(std::bad_alloc, std::runtime_error)
484 if(master)
485 return master->reset();
486 threads::arlock h(get_lua_lock());
487 auto state = &state_internal_t::get(this);
488 if(lua_handle) {
489 lua_State* tmp = lua_newstate(state::builtin_alloc, this);
490 if(!tmp)
491 throw std::runtime_error("Can't re-initialize Lua interpretter");
492 lua_close(lua_handle);
493 for(auto& i : state->callbacks)
494 i.second->clear();
495 lua_handle = tmp;
496 } else {
497 //Initialize new.
498 lua_handle = lua_newstate(state::builtin_alloc, this);
499 if(!lua_handle)
500 throw std::runtime_error("Can't initialize Lua interpretter");
502 for(auto i : state->function_groups)
503 i.first->request_callback([this](std::string name, function* func) -> void {
504 register_function(*this, name, func);
506 for(auto i : state->class_groups)
507 i.first->request_callback([this](std::string name, class_base* clazz) -> void {
508 register_class(*this, name, clazz);
512 void state::deinit() throw()
514 if(master)
515 return master->deinit();
516 if(lua_handle)
517 lua_close(lua_handle);
518 lua_handle = NULL;
521 void state::add_function_group(function_group& group)
523 threads::arlock h(get_lua_lock());
524 auto& state = state_internal_t::get(this);
525 state.function_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
526 function* func) -> void {
527 this->function_callback(name, func);
528 }, [this](function_group* x) {
529 threads::arlock h(get_lua_lock());
530 auto state = state_internal_t::get_soft(this);
531 if(!state) return;
532 for(auto i = state->function_groups.begin(); i != state->function_groups.end();)
533 if(i->first == x)
534 i = state->function_groups.erase(i);
535 else
536 i++;
537 })));
540 void state::add_class_group(class_group& group)
542 threads::arlock h(get_lua_lock());
543 auto& state = state_internal_t::get(this);
544 state.class_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
545 class_base* clazz) -> void {
546 this->class_callback(name, clazz);
547 }, [this](class_group* x) {
548 threads::arlock h(get_lua_lock());
549 auto state = state_internal_t::get_soft(this);
550 if(!state) return;
551 for(auto i = state->class_groups.begin(); i != state->class_groups.end();)
552 if(i->first == x)
553 i = state->class_groups.erase(i);
554 else
555 i++;
556 })));
559 void state::function_callback(const std::string& name, function* func)
561 if(master)
562 return master->function_callback(name, func);
563 if(lua_handle)
564 register_function(*this, name, func);
567 void state::class_callback(const std::string& name, class_base* clazz)
569 if(master)
570 return master->class_callback(name, clazz);
571 if(lua_handle)
572 register_class(*this, name, clazz);
575 bool state::do_once(void* key)
577 if(master)
578 return master->do_once(key);
579 pushlightuserdata(key);
580 rawget(LUA_REGISTRYINDEX);
581 if(type(-1) == LUA_TNIL) {
582 pop(1);
583 pushlightuserdata(key);
584 pushlightuserdata(key);
585 rawset(LUA_REGISTRYINDEX);
586 return true;
587 } else {
588 pop(1);
589 return false;
593 std::list<state::callback_list*> state::get_callbacks()
595 if(master)
596 return master->get_callbacks();
597 threads::arlock h(get_lua_lock());
598 auto state = state_internal_t::get_soft(this);
599 std::list<callback_list*> r;
600 if(state)
601 for(auto i : state->callbacks)
602 r.push_back(i.second);
603 return r;
606 void state::do_register(const std::string& name, callback_list& callback)
608 threads::arlock h(get_lua_lock());
609 auto& state = state_internal_t::get(this);
610 if(state.callbacks.count(name)) return;
611 state.callbacks[name] = &callback;
614 void state::do_unregister(const std::string& name, callback_list& callback)
616 threads::arlock h(get_lua_lock());
617 auto state = state_internal_t::get_soft(this);
618 if(state && state->callbacks.count(name) && state->callbacks[name] == &callback)
619 state->callbacks.erase(name);
622 state::callback_list::callback_list(state& _L, const std::string& _name, const std::string& fncbname)
623 : L(_L), name(_name), fn_cbname(fncbname)
625 L.do_register(name, *this);
628 state::callback_list::~callback_list()
630 L.do_unregister(name, *this);
631 if(!L.handle())
632 return;
633 for(auto& i : callbacks) {
634 L.pushlightuserdata(&i);
635 L.pushnil();
636 L.rawset(LUA_REGISTRYINDEX);
640 void state::callback_list::_register(state& _L)
642 callbacks.push_back(0);
643 _L.pushlightuserdata(&*callbacks.rbegin());
644 _L.pushvalue(-2);
645 _L.rawset(LUA_REGISTRYINDEX);
648 void state::callback_list::_unregister(state& _L)
650 for(auto i = callbacks.begin(); i != callbacks.end();) {
651 _L.pushlightuserdata(&*i);
652 _L.rawget(LUA_REGISTRYINDEX);
653 if(_L.rawequal(-1, -2)) {
654 char* key = &*i;
655 _L.pushlightuserdata(key);
656 _L.pushnil();
657 _L.rawset(LUA_REGISTRYINDEX);
658 i = callbacks.erase(i);
659 } else
660 i++;
661 _L.pop(1);
665 function_group::function_group()
669 function_group::~function_group()
671 threads::arlock h(get_lua_lock());
672 auto state = fgroup_internal_t::get_soft(this);
673 if(!state) return;
674 for(auto i : state->dcallbacks)
675 i.second(this);
676 fgroup_internal_t::clear(this);
679 void function_group::request_callback(std::function<void(std::string, function*)> cb)
681 threads::arlock h(get_lua_lock());
682 auto state = fgroup_internal_t::get_soft(this);
683 if(!state) return;
684 for(auto i : state->functions)
685 cb(i.first, i.second);
688 int function_group::add_callback(std::function<void(std::string, function*)> cb,
689 std::function<void(function_group*)> dcb)
691 threads::arlock h(get_lua_lock());
692 auto& state = fgroup_internal_t::get(this);
693 int handle = state.next_handle++;
694 state.callbacks[handle] = cb;
695 state.dcallbacks[handle] = dcb;
696 for(auto i : state.functions)
697 cb(i.first, i.second);
698 return handle;
701 void function_group::drop_callback(int handle)
703 threads::arlock h(get_lua_lock());
704 auto state = fgroup_internal_t::get_soft(this);
705 if(!state) return;
706 state->callbacks.erase(handle);
709 void function_group::do_register(const std::string& name, function& fun)
711 threads::arlock h(get_lua_lock());
712 auto& state = fgroup_internal_t::get(this);
713 if(state.functions.count(name)) return;
714 state.functions[name] = &fun;
715 for(auto i : state.callbacks)
716 i.second(name, &fun);
719 void function_group::do_unregister(const std::string& name, function& fun)
721 threads::arlock h(get_lua_lock());
722 auto state = fgroup_internal_t::get_soft(this);
723 if(!state || !state->functions.count(name) || state->functions[name] != &fun) return;
724 state->functions.erase(name);
725 for(auto i : state->callbacks)
726 i.second(name, NULL);
729 class_group::class_group()
733 class_group::~class_group()
735 threads::arlock h(get_lua_lock());
736 auto state = cgroup_internal_t::get_soft(this);
737 if(!state) return;
738 for(auto i : state->dcallbacks)
739 i.second(this);
740 cgroup_internal_t::clear(this);
743 void class_group::request_callback(std::function<void(std::string, class_base*)> cb)
745 threads::arlock h(get_lua_lock());
746 auto state = cgroup_internal_t::get_soft(this);
747 if(!state) return;
748 for(auto i : state->classes)
749 cb(i.first, i.second);
752 int class_group::add_callback(std::function<void(std::string, class_base*)> cb,
753 std::function<void(class_group*)> dcb)
755 threads::arlock h(get_lua_lock());
756 auto& state = cgroup_internal_t::get(this);
757 int handle = state.next_handle++;
758 state.callbacks[handle] = cb;
759 state.dcallbacks[handle] = dcb;
760 for(auto i : state.classes)
761 cb(i.first, i.second);
762 return handle;
765 void class_group::drop_callback(int handle)
767 threads::arlock h(get_lua_lock());
768 auto state = cgroup_internal_t::get_soft(this);
769 if(!state) return;
770 state->callbacks.erase(handle);
773 void class_group::do_register(const std::string& name, class_base& fun)
775 threads::arlock h(get_lua_lock());
776 auto& state = cgroup_internal_t::get(this);
777 if(state.classes.count(name)) return;
778 state.classes[name] = &fun;
779 for(auto i : state.callbacks)
780 i.second(name, &fun);
783 void class_group::do_unregister(const std::string& name, class_base& fun)
785 threads::arlock h(get_lua_lock());
786 auto state = cgroup_internal_t::get_soft(this);
787 if(!state || !state->classes.count(name) || state->classes[name] != &fun) return;
788 state->classes.erase(name);
789 for(auto i : state->callbacks)
790 i.second(name, NULL);
793 std::list<class_ops>& userdata_recogn_fns()
795 static std::list<class_ops> x;
796 return x;
799 std::string try_recognize_userdata(state& state, int index)
801 for(auto i : userdata_recogn_fns())
802 if(i.is(state, index))
803 return i.name();
804 //Hack: Lua builtin file objects and classobjs.
805 if(state.getmetatable(index)) {
806 state.pushstring("FILE*");
807 state.rawget(LUA_REGISTRYINDEX);
808 if(state.rawequal(-1, -2)) {
809 state.pop(2);
810 return "FILE*";
812 state.pop(1);
813 state.pushlightuserdata(&classtable_meta_key);
814 state.rawget(LUA_REGISTRYINDEX);
815 if(state.rawequal(-1, -2)) {
816 state.pop(2);
817 return "classobj";
819 state.pop(1);
821 return "unknown";
824 std::string try_print_userdata(state& L, int index)
826 for(auto i : userdata_recogn_fns())
827 if(i.is(L, index))
828 return i.print(L, index);
829 //Hack: classobjs.
830 if(L.getmetatable(index)) {
831 L.pushlightuserdata(&classtable_meta_key);
832 L.rawget(LUA_REGISTRYINDEX);
833 if(L.rawequal(-1, -2)) {
834 L.pop(2);
835 std::string cname = ((class_info*)L.touserdata(index))->obj->get_name();
836 return cname;
838 L.pop(1);
840 return "no data available";
843 int state::vararg_tag::pushargs(state& L)
845 int e = 0;
846 for(auto i : args) {
847 if(i == "")
848 L.pushnil();
849 else if(i == "true")
850 L.pushboolean(true);
851 else if(i == "false")
852 L.pushboolean(false);
853 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i))
854 L.pushnumber(strtod(i.c_str(), NULL));
855 else if(i[0] == ':')
856 L.pushlstring(i.substr(1));
857 else
858 L.pushlstring(i);
859 e++;
861 return e;
864 class_base* class_base::lookup(state& L, const std::string& _name)
866 if(lookup_and_push(L, _name)) {
867 class_base* obj = ((class_info*)L.touserdata(-1))->obj;
868 L.pop(1);
869 return obj;
871 return NULL;
874 bool class_base::lookup_and_push(state& L, const std::string& _name)
876 L.pushlightuserdata(&classtable_key);
877 L.rawget(LUA_REGISTRYINDEX);
878 if(L.type(-1) == LUA_TNIL) {
879 //No classes.
880 L.pop(1);
881 return false;
883 //On top of stack there is class table.
884 L.pushlstring(_name);
885 L.rawget(-2);
886 if(L.type(-1) == LUA_TNIL) {
887 //Not found.
888 L.pop(2);
889 return false;
891 L.insert(-2);
892 L.pop(1);
893 return true;
896 std::set<std::string> class_base::all_classes(state& L)
898 L.pushlightuserdata(&classtable_key);
899 L.rawget(LUA_REGISTRYINDEX);
900 if(L.type(-1) == LUA_TNIL) {
901 //No classes.
902 L.pop(1);
903 return std::set<std::string>();
905 std::set<std::string> r;
906 L.pushnil();
907 while(L.next(-2)) {
908 L.pop(1); //Pop value.
909 if(L.type(-1) == LUA_TSTRING) r.insert(L.tostring(-1));
911 L.pop(1);
912 return r;
915 void class_base::register_static(state& L)
917 again:
918 L.pushlightuserdata(&classtable_key);
919 L.rawget(LUA_REGISTRYINDEX);
920 if(L.type(-1) == LUA_TNIL) {
921 L.pop(1);
922 L.pushlightuserdata(&classtable_key);
923 L.newtable();
924 L.rawset(LUA_REGISTRYINDEX);
925 goto again;
927 //On top of stack there is class table.
928 L.pushlstring(name);
929 L.rawget(-2);
930 if(L.type(-1) != LUA_TNIL) {
931 //Already registered.
932 L.pop(2);
933 return;
935 L.pop(1);
936 L.pushlstring(name);
937 //Now construct the object.
938 class_info* ci = (class_info*)L.newuserdata(sizeof(class_info));
939 ci->obj = this;
940 again2:
941 L.pushlightuserdata(&classtable_meta_key);
942 L.rawget(LUA_REGISTRYINDEX);
943 if(L.type(-1) == LUA_TNIL) {
944 L.pop(1);
945 L.pushlightuserdata(&classtable_meta_key);
946 L.newtable();
947 L.pushstring("__index");
948 L.push_trampoline(class_info::index, 0);
949 L.rawset(-3);
950 L.pushstring("__newindex");
951 L.push_trampoline(class_info::newindex, 0);
952 L.rawset(-3);
953 L.pushstring("__pairs");
954 L.push_trampoline(class_info::pairs, 0);
955 L.rawset(-3);
956 L.rawset(LUA_REGISTRYINDEX);
957 goto again2;
959 L.setmetatable(-2);
960 L.rawset(-3);
961 L.pop(1);
964 void class_base::delayed_register()
966 group.do_register(name, *this);
969 functions::functions(function_group& grp, const std::string& basetable, std::initializer_list<entry> fnlist)
971 std::string base = (basetable == "") ? "" : (basetable + ".");
972 for(auto i : fnlist)
973 funcs.insert(new fn(grp, base + i.name, i.func));
976 functions::~functions()
978 for(auto i : funcs)
979 delete i;
982 functions::fn::fn(function_group& grp, const std::string& name, std::function<int(state& L, parameters& P)> _func)
983 : function(grp, name)
985 func = _func;
988 functions::fn::~fn() throw()
992 int functions::fn::invoke(state& L)
994 lua::parameters P(L, fname);
995 return func(L, P);