Small whitespace cleanup
[lsnes.git] / src / library / lua.cpp
blob947e3312938b87183f59c18c40d24644b72869b1
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 void state::run_interruptable(std::function<void()> fn, unsigned in, unsigned out)
418 pushnumber(out);
419 pushlightuserdata(&fn);
420 pushcfunction(run_interruptable_trampoline);
421 insert(-(int)in - 3);
422 int r = pcall(in + 2, out, 0);
423 if(r == LUA_OK) {
424 //Nothing.
425 } else if(r == LUA_ERRRUN) {
426 throw std::runtime_error(tostring(-1));
427 } else if(r == LUA_ERRMEM) {
428 throw std::runtime_error("Lua out of memory");
429 } else if(r == LUA_ERRERR) {
430 throw std::runtime_error("Lua double fault");
431 #ifdef LUA_ERRGCMM
432 } else if(r == LUA_ERRGCMM) {
433 throw std::runtime_error("Lua fault in garbage collector");
434 #endif
438 bool state::charge_memory(size_t amount, bool release)
440 if(master) return master->charge_memory(amount, release);
441 if(release) {
442 if(memory_use > amount)
443 memory_use -= amount;
444 else
445 memory_use = 0;
446 return true;
448 if(!interruptable) {
449 //Give everything we got.
450 memory_use += amount;
451 return true;
452 } else {
453 //Check limit and refuse allocations too large.
454 if(memory_use + amount > memory_limit || memory_use + amount < amount)
455 return false;
456 memory_use += amount;
457 return true;
461 function::function(function_group& _group, const std::string& func) throw(std::bad_alloc)
462 : group(_group)
464 group.do_register(fname = func, *this);
467 function::~function() throw()
469 group.do_unregister(fname, *this);
472 class_base::class_base(class_group& _group, const std::string& _name)
473 : group(_group), name(_name)
475 registered = false;
478 class_base::~class_base() throw()
480 if(registered)
481 group.do_unregister(name, *this);
484 void state::reset() throw(std::bad_alloc, std::runtime_error)
486 if(master)
487 return master->reset();
488 threads::arlock h(get_lua_lock());
489 auto state = &state_internal_t::get(this);
490 if(lua_handle) {
491 lua_State* tmp = lua_newstate(state::builtin_alloc, this);
492 if(!tmp)
493 throw std::runtime_error("Can't re-initialize Lua interpretter");
494 lua_close(lua_handle);
495 for(auto& i : state->callbacks)
496 i.second->clear();
497 lua_handle = tmp;
498 } else {
499 //Initialize new.
500 lua_handle = lua_newstate(state::builtin_alloc, this);
501 if(!lua_handle)
502 throw std::runtime_error("Can't initialize Lua interpretter");
504 for(auto i : state->function_groups)
505 i.first->request_callback([this](std::string name, function* func) -> void {
506 register_function(*this, name, func);
508 for(auto i : state->class_groups)
509 i.first->request_callback([this](std::string name, class_base* clazz) -> void {
510 register_class(*this, name, clazz);
514 void state::deinit() throw()
516 if(master)
517 return master->deinit();
518 if(lua_handle)
519 lua_close(lua_handle);
520 lua_handle = NULL;
523 void state::add_function_group(function_group& group)
525 threads::arlock h(get_lua_lock());
526 auto& state = state_internal_t::get(this);
527 state.function_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
528 function* func) -> void {
529 this->function_callback(name, func);
530 }, [this](function_group* x) {
531 threads::arlock h(get_lua_lock());
532 auto state = state_internal_t::get_soft(this);
533 if(!state) return;
534 for(auto i = state->function_groups.begin(); i != state->function_groups.end();)
535 if(i->first == x)
536 i = state->function_groups.erase(i);
537 else
538 i++;
539 })));
542 void state::add_class_group(class_group& group)
544 threads::arlock h(get_lua_lock());
545 auto& state = state_internal_t::get(this);
546 state.class_groups.insert(std::make_pair(&group, group.add_callback([this](const std::string& name,
547 class_base* clazz) -> void {
548 this->class_callback(name, clazz);
549 }, [this](class_group* x) {
550 threads::arlock h(get_lua_lock());
551 auto state = state_internal_t::get_soft(this);
552 if(!state) return;
553 for(auto i = state->class_groups.begin(); i != state->class_groups.end();)
554 if(i->first == x)
555 i = state->class_groups.erase(i);
556 else
557 i++;
558 })));
561 void state::function_callback(const std::string& name, function* func)
563 if(master)
564 return master->function_callback(name, func);
565 if(lua_handle)
566 register_function(*this, name, func);
569 void state::class_callback(const std::string& name, class_base* clazz)
571 if(master)
572 return master->class_callback(name, clazz);
573 if(lua_handle)
574 register_class(*this, name, clazz);
577 bool state::do_once(void* key)
579 if(master)
580 return master->do_once(key);
581 pushlightuserdata(key);
582 rawget(LUA_REGISTRYINDEX);
583 if(type(-1) == LUA_TNIL) {
584 pop(1);
585 pushlightuserdata(key);
586 pushlightuserdata(key);
587 rawset(LUA_REGISTRYINDEX);
588 return true;
589 } else {
590 pop(1);
591 return false;
595 std::list<state::callback_list*> state::get_callbacks()
597 if(master)
598 return master->get_callbacks();
599 threads::arlock h(get_lua_lock());
600 auto state = state_internal_t::get_soft(this);
601 std::list<callback_list*> r;
602 if(state)
603 for(auto i : state->callbacks)
604 r.push_back(i.second);
605 return r;
608 void state::do_register(const std::string& name, callback_list& callback)
610 threads::arlock h(get_lua_lock());
611 auto& state = state_internal_t::get(this);
612 if(state.callbacks.count(name)) return;
613 state.callbacks[name] = &callback;
616 void state::do_unregister(const std::string& name, callback_list& callback)
618 threads::arlock h(get_lua_lock());
619 auto state = state_internal_t::get_soft(this);
620 if(state && state->callbacks.count(name) && state->callbacks[name] == &callback)
621 state->callbacks.erase(name);
624 state::callback_list::callback_list(state& _L, const std::string& _name, const std::string& fncbname)
625 : L(_L), name(_name), fn_cbname(fncbname)
627 L.do_register(name, *this);
630 state::callback_list::~callback_list()
632 L.do_unregister(name, *this);
633 if(!L.handle())
634 return;
635 for(auto& i : callbacks) {
636 L.pushlightuserdata(&i);
637 L.pushnil();
638 L.rawset(LUA_REGISTRYINDEX);
642 void state::callback_list::_register(state& _L)
644 callbacks.push_back(0);
645 _L.pushlightuserdata(&*callbacks.rbegin());
646 _L.pushvalue(-2);
647 _L.rawset(LUA_REGISTRYINDEX);
650 void state::callback_list::_unregister(state& _L)
652 for(auto i = callbacks.begin(); i != callbacks.end();) {
653 _L.pushlightuserdata(&*i);
654 _L.rawget(LUA_REGISTRYINDEX);
655 if(_L.rawequal(-1, -2)) {
656 char* key = &*i;
657 _L.pushlightuserdata(key);
658 _L.pushnil();
659 _L.rawset(LUA_REGISTRYINDEX);
660 i = callbacks.erase(i);
661 } else
662 i++;
663 _L.pop(1);
667 function_group::function_group()
671 function_group::~function_group()
673 threads::arlock h(get_lua_lock());
674 auto state = fgroup_internal_t::get_soft(this);
675 if(!state) return;
676 for(auto i : state->dcallbacks)
677 i.second(this);
678 fgroup_internal_t::clear(this);
681 void function_group::request_callback(std::function<void(std::string, function*)> cb)
683 threads::arlock h(get_lua_lock());
684 auto state = fgroup_internal_t::get_soft(this);
685 if(!state) return;
686 for(auto i : state->functions)
687 cb(i.first, i.second);
690 int function_group::add_callback(std::function<void(std::string, function*)> cb,
691 std::function<void(function_group*)> dcb)
693 threads::arlock h(get_lua_lock());
694 auto& state = fgroup_internal_t::get(this);
695 int handle = state.next_handle++;
696 state.callbacks[handle] = cb;
697 state.dcallbacks[handle] = dcb;
698 for(auto i : state.functions)
699 cb(i.first, i.second);
700 return handle;
703 void function_group::drop_callback(int handle)
705 threads::arlock h(get_lua_lock());
706 auto state = fgroup_internal_t::get_soft(this);
707 if(!state) return;
708 state->callbacks.erase(handle);
711 void function_group::do_register(const std::string& name, function& fun)
713 threads::arlock h(get_lua_lock());
714 auto& state = fgroup_internal_t::get(this);
715 if(state.functions.count(name)) return;
716 state.functions[name] = &fun;
717 for(auto i : state.callbacks)
718 i.second(name, &fun);
721 void function_group::do_unregister(const std::string& name, function& fun)
723 threads::arlock h(get_lua_lock());
724 auto state = fgroup_internal_t::get_soft(this);
725 if(!state || !state->functions.count(name) || state->functions[name] != &fun) return;
726 state->functions.erase(name);
727 for(auto i : state->callbacks)
728 i.second(name, NULL);
731 class_group::class_group()
735 class_group::~class_group()
737 threads::arlock h(get_lua_lock());
738 auto state = cgroup_internal_t::get_soft(this);
739 if(!state) return;
740 for(auto i : state->dcallbacks)
741 i.second(this);
742 cgroup_internal_t::clear(this);
745 void class_group::request_callback(std::function<void(std::string, class_base*)> cb)
747 threads::arlock h(get_lua_lock());
748 auto state = cgroup_internal_t::get_soft(this);
749 if(!state) return;
750 for(auto i : state->classes)
751 cb(i.first, i.second);
754 int class_group::add_callback(std::function<void(std::string, class_base*)> cb,
755 std::function<void(class_group*)> dcb)
757 threads::arlock h(get_lua_lock());
758 auto& state = cgroup_internal_t::get(this);
759 int handle = state.next_handle++;
760 state.callbacks[handle] = cb;
761 state.dcallbacks[handle] = dcb;
762 for(auto i : state.classes)
763 cb(i.first, i.second);
764 return handle;
767 void class_group::drop_callback(int handle)
769 threads::arlock h(get_lua_lock());
770 auto state = cgroup_internal_t::get_soft(this);
771 if(!state) return;
772 state->callbacks.erase(handle);
775 void class_group::do_register(const std::string& name, class_base& fun)
777 threads::arlock h(get_lua_lock());
778 auto& state = cgroup_internal_t::get(this);
779 if(state.classes.count(name)) return;
780 state.classes[name] = &fun;
781 for(auto i : state.callbacks)
782 i.second(name, &fun);
785 void class_group::do_unregister(const std::string& name, class_base& fun)
787 threads::arlock h(get_lua_lock());
788 auto state = cgroup_internal_t::get_soft(this);
789 if(!state || !state->classes.count(name) || state->classes[name] != &fun) return;
790 state->classes.erase(name);
791 for(auto i : state->callbacks)
792 i.second(name, NULL);
795 std::list<class_ops>& userdata_recogn_fns()
797 static std::list<class_ops> x;
798 return x;
801 std::string try_recognize_userdata(state& state, int index)
803 for(auto i : userdata_recogn_fns())
804 if(i.is(state, index))
805 return i.name();
806 //Hack: Lua builtin file objects and classobjs.
807 if(state.getmetatable(index)) {
808 state.pushstring("FILE*");
809 state.rawget(LUA_REGISTRYINDEX);
810 if(state.rawequal(-1, -2)) {
811 state.pop(2);
812 return "FILE*";
814 state.pop(1);
815 state.pushlightuserdata(&classtable_meta_key);
816 state.rawget(LUA_REGISTRYINDEX);
817 if(state.rawequal(-1, -2)) {
818 state.pop(2);
819 return "classobj";
821 state.pop(1);
823 return "unknown";
826 std::string try_print_userdata(state& L, int index)
828 for(auto i : userdata_recogn_fns())
829 if(i.is(L, index))
830 return i.print(L, index);
831 //Hack: classobjs.
832 if(L.getmetatable(index)) {
833 L.pushlightuserdata(&classtable_meta_key);
834 L.rawget(LUA_REGISTRYINDEX);
835 if(L.rawequal(-1, -2)) {
836 L.pop(2);
837 std::string cname = ((class_info*)L.touserdata(index))->obj->get_name();
838 return cname;
840 L.pop(1);
842 return "no data available";
845 int state::vararg_tag::pushargs(state& L)
847 int e = 0;
848 for(auto i : args) {
849 if(i == "")
850 L.pushnil();
851 else if(i == "true")
852 L.pushboolean(true);
853 else if(i == "false")
854 L.pushboolean(false);
855 else if(regex_match("[+-]?(|0|[1-9][0-9]*)(.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?", i))
856 L.pushnumber(strtod(i.c_str(), NULL));
857 else if(i[0] == ':')
858 L.pushlstring(i.substr(1));
859 else
860 L.pushlstring(i);
861 e++;
863 return e;
866 class_base* class_base::lookup(state& L, const std::string& _name)
868 if(lookup_and_push(L, _name)) {
869 class_base* obj = ((class_info*)L.touserdata(-1))->obj;
870 L.pop(1);
871 return obj;
873 return NULL;
876 bool class_base::lookup_and_push(state& L, const std::string& _name)
878 L.pushlightuserdata(&classtable_key);
879 L.rawget(LUA_REGISTRYINDEX);
880 if(L.type(-1) == LUA_TNIL) {
881 //No classes.
882 L.pop(1);
883 return false;
885 //On top of stack there is class table.
886 L.pushlstring(_name);
887 L.rawget(-2);
888 if(L.type(-1) == LUA_TNIL) {
889 //Not found.
890 L.pop(2);
891 return false;
893 L.insert(-2);
894 L.pop(1);
895 return true;
898 std::set<std::string> class_base::all_classes(state& L)
900 L.pushlightuserdata(&classtable_key);
901 L.rawget(LUA_REGISTRYINDEX);
902 if(L.type(-1) == LUA_TNIL) {
903 //No classes.
904 L.pop(1);
905 return std::set<std::string>();
907 std::set<std::string> r;
908 L.pushnil();
909 while(L.next(-2)) {
910 L.pop(1); //Pop value.
911 if(L.type(-1) == LUA_TSTRING) r.insert(L.tostring(-1));
913 L.pop(1);
914 return r;
917 void class_base::register_static(state& L)
919 again:
920 L.pushlightuserdata(&classtable_key);
921 L.rawget(LUA_REGISTRYINDEX);
922 if(L.type(-1) == LUA_TNIL) {
923 L.pop(1);
924 L.pushlightuserdata(&classtable_key);
925 L.newtable();
926 L.rawset(LUA_REGISTRYINDEX);
927 goto again;
929 //On top of stack there is class table.
930 L.pushlstring(name);
931 L.rawget(-2);
932 if(L.type(-1) != LUA_TNIL) {
933 //Already registered.
934 L.pop(2);
935 return;
937 L.pop(1);
938 L.pushlstring(name);
939 //Now construct the object.
940 class_info* ci = (class_info*)L.newuserdata(sizeof(class_info));
941 ci->obj = this;
942 again2:
943 L.pushlightuserdata(&classtable_meta_key);
944 L.rawget(LUA_REGISTRYINDEX);
945 if(L.type(-1) == LUA_TNIL) {
946 L.pop(1);
947 L.pushlightuserdata(&classtable_meta_key);
948 L.newtable();
949 L.pushstring("__index");
950 L.push_trampoline(class_info::index, 0);
951 L.rawset(-3);
952 L.pushstring("__newindex");
953 L.push_trampoline(class_info::newindex, 0);
954 L.rawset(-3);
955 L.pushstring("__pairs");
956 L.push_trampoline(class_info::pairs, 0);
957 L.rawset(-3);
958 L.rawset(LUA_REGISTRYINDEX);
959 goto again2;
961 L.setmetatable(-2);
962 L.rawset(-3);
963 L.pop(1);
966 void class_base::delayed_register()
968 group.do_register(name, *this);
971 functions::functions(function_group& grp, const std::string& basetable, std::initializer_list<entry> fnlist)
973 std::string base = (basetable == "") ? "" : (basetable + ".");
974 for(auto i : fnlist)
975 funcs.insert(new fn(grp, base + i.name, i.func));
978 functions::~functions()
980 for(auto i : funcs)
981 delete i;
984 functions::fn::fn(function_group& grp, const std::string& name, std::function<int(state& L, parameters& P)> _func)
985 : function(grp, name)
987 func = _func;
990 functions::fn::~fn() throw()
994 int functions::fn::invoke(state& L)
996 lua::parameters P(L, fname);
997 return func(L, P);