Started to make things work: show the board.
[tagua.git] / src / luaapi / genericwrapper.h
blob2ef677a2563d9a543d10b273cd1d9c845be683d9
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@sns.it>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 */
11 #ifndef LUAAPI__GENERICWRAPPER_H
12 #define LUAAPI__GENERICWRAPPER_H
14 extern "C" {
15 #include <lua.h>
16 #include <lualib.h>
17 #include <lauxlib.h>
18 #include "lfunclib.h"
20 #include <iostream>
21 #include <QString>
22 #include "common.h"
24 namespace Loader { class Context; }
26 namespace LuaApi {
28 #define WRAP_0(func, selftype, restype) \
29 static int func(lua_State* l) { \
30 selftype* self = retrieve(l, 1); \
31 CAT0(lua_push, restype)(l, self->func()); \
32 return 1; \
35 #define PROPERTY_RW(PROP, GET, SET, restype) \
36 static int get_##PROP(lua_State* l) { \
37 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
38 return 1; \
39 } \
41 static int set_##PROP(lua_State* l) { \
42 retrieve(l, 1, DontCheck)->SET( lua_to##restype(l, 2) ); \
43 return 0; \
46 #define PROPERTY_RW_TYPE(PROP, GET, SET, restype, TYPE) \
47 static int get_##PROP(lua_State* l) { \
48 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
49 return 1; \
50 } \
52 static int set_##PROP(lua_State* l) { \
53 retrieve(l, 1, DontCheck)->SET( TYPE(lua_to##restype(l, 2)) ); \
54 return 0; \
57 #define PROPERTY_RW_CLASS(PROP, GET, SET, CLASS) \
58 static int get_##PROP(lua_State* l) { \
59 Wrapper<CLASS>::allocate(l, new CLASS(retrieve(l, 1, DontCheck)->GET())); \
60 return 1; \
61 } \
63 static int set_##PROP(lua_State* l) { \
64 retrieve(l, 1, DontCheck)->SET( *Wrapper<CLASS>::retrieve(l, 2, AssertOk) ); \
65 return 0; \
68 #define PROPERTY_RO(PROP, GET, restype) \
69 static int get_##PROP(lua_State* l) { \
70 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
71 return 1; \
74 #define P_PROPERTY_RW(PROP, GET, SET, restype) \
75 static int get_##PROP(lua_State* l) { \
76 lua_push##restype(l, (*retrieve(l, 1, DontCheck))->GET()); \
77 return 1; \
78 } \
80 static int set_##PROP(lua_State* l) { \
81 (*retrieve(l, 1, DontCheck))->SET( lua_to##restype(l, 2) ); \
82 return 0; \
85 #define P_PROPERTY_RW_TYPE(PROP, GET, SET, restype, TYPE) \
86 static int get_##PROP(lua_State* l) { \
87 lua_push##restype(l, (*retrieve(l, 1, DontCheck))->GET()); \
88 return 1; \
89 } \
91 static int set_##PROP(lua_State* l) { \
92 (*retrieve(l, 1, DontCheck))->SET( TYPE(lua_to##restype(l, 2)) ); \
93 return 0; \
96 #define P_PROPERTY_RO_TYPE(PROP, GET, restype, TYPE) \
97 static int get_##PROP(lua_State* l) { \
98 lua_push##restype(l, (*retrieve(l, 1, DontCheck))->GET()); \
99 return 1; \
102 #define P_PROPERTY_RW_CLASS(PROP, GET, SET, CLASS) \
103 static int get_##PROP(lua_State* l) { \
104 Wrapper<CLASS>::allocate(l, new CLASS((*retrieve(l, 1, DontCheck))->GET())); \
105 return 1; \
108 static int set_##PROP(lua_State* l) { \
109 (*retrieve(l, 1, DontCheck))->SET( *Wrapper<CLASS>::retrieve(l, 2, AssertOk) ); \
110 return 0; \
113 #define P_PROPERTY_RO_CLASS(PROP, GET, CLASS) \
114 static int get_##PROP(lua_State* l) { \
115 Wrapper<CLASS>::allocate(l, new CLASS((*retrieve(l, 1, DontCheck))->GET())); \
116 return 1; \
119 #define P_PROPERTY_RW_P_CLASS(PROP, GET, SET, CLASS) \
120 static int get_##PROP(lua_State* l) { \
121 Wrapper<CLASS>::allocate(l, (*retrieve(l, 1, DontCheck))->GET()); \
122 return 1; \
125 static int set_##PROP(lua_State* l) { \
126 (*retrieve(l, 1, DontCheck))->SET( *Wrapper<CLASS>::retrieve(l, 2, AssertOk) ); \
127 return 0; \
130 #define P_PROPERTY_RO_P_CLASS(PROP, GET, CLASS) \
131 static int get_##PROP(lua_State* l) { \
132 Wrapper<CLASS>::allocate(l, (*retrieve(l, 1, DontCheck))->GET()); \
133 return 1; \
136 #define P_PROPERTY_RO(PROP, GET, restype) \
137 static int get_##PROP(lua_State* l) { \
138 lua_push##restype(l, (*retrieve(l, 1, DontCheck))->GET()); \
139 return 1; \
142 #define P_PROPERTY_RO_QSTRING(PROP, GET) \
143 static int get_##PROP(lua_State* l) { \
144 QString s = (*retrieve(l, 1, DontCheck))->GET(); \
145 lua_pushstring(l, s.toAscii().constData()); \
146 return 1; \
149 #define P_PROPERTY_RW_QSTRING(PROP, GET, SET) \
150 static int get_##PROP(lua_State* l) { \
151 QString s = (*retrieve(l, 1, DontCheck))->GET(); \
152 lua_pushstring(l, s.toAscii().constData()); \
153 return 1; \
156 static int set_##PROP(lua_State* l) { \
157 (*retrieve(l, 1, DontCheck))->SET( QString(lua_tostring(l, 2)) ); \
158 return 0; \
161 #define SET_PROPERTY_RW(LUA, PROP) \
162 set_property(LUA, #PROP, get_##PROP, set_##PROP);
164 #define SET_PROPERTY_RO(LUA, PROP) \
165 set_property(LUA, #PROP, get_##PROP, NULL);
168 #define LOADING_CONTEXT "kboard_loading_context"
169 #define CURRENT_DIRECTORY "kboard_script_curr_dir"
170 #define API_LOADER "kboard_api_loader"
175 class StackCheck {
176 lua_State* l;
177 int top;
178 public:
179 StackCheck(lua_State* l, int expect = 0) : l(l) {
180 top = lua_gettop(l) + expect;
183 ~StackCheck() {
184 if (lua_gettop(l) != top) {
185 std::cout << "Wrong stack size!\n\texpected = " << top <<
186 "\n\tactual = " << lua_gettop(l) << std::endl;
193 enum CheckStrenght {
194 DontCheck,
195 Check,
196 AssertOk
200 template <typename T>
201 class Wrapper;
204 //BEGIN GenericWrappeBase------------------------------------------------------
206 class GenericWrapperBase {
207 public:
208 static QString file_path(lua_State* l, const QString& f);
210 static Loader::Context* retrieve_context(lua_State* l);
213 * Add property f to the table at @a index.
215 static void set_property(lua_State* l, const char* name, lua_CFunction get,
216 lua_CFunction set = NULL, int index = -1);
219 * Add method f to the table at @a index.
221 static void set_method(lua_State* l, lua_CFunction f, const char* name, int index = -1);
224 * Add meta method f to the table at @a index.
226 static void set_meta_method(lua_State* l, lua_CFunction f, const char* name, int index = -1);
229 * Object index read event
231 static int object_meta_index_event(lua_State* l);
234 * Object index write event
236 static int object_meta_newindex_event(lua_State* l);
239 //END GenericWrapperBase-------------------------------------------------------
242 //BEGIN GenericWrapper---------------------------------------------------------
244 template <typename T>
245 class GenericWrapper : public GenericWrapperBase {
246 public:
248 static void register_class(lua_State* l);
251 * Retrieve a wrapped object on the stack.
253 static T* retrieve(lua_State* l, int index = -1, CheckStrenght check = Check);
256 * Destroy a wrapped object of type T.
258 static int deallocate(lua_State* l);
261 * Wrap an object of type T in a Lua userdatum.
262 * Lua takes ownership of the object, so that it is
263 * automatically disposed by the Lua garbage collector.
265 static void allocate(lua_State* l, T* x);
268 * Create the factory class and static metatable.
270 static void create_prototype(lua_State* l, const char* prototype_name);
273 * Calls the Wrapper&lt;T&gt; constructor
275 static int constructor_wrapper(lua_State* l);
278 * Pushes this object's meta table.
280 static void push_meta_table(lua_State* l);
283 template<typename T>
284 void GenericWrapper<T>::register_class(lua_State* l) {
285 create_prototype(l, Wrapper<T>::class_name());
288 template<typename T>
289 T* GenericWrapper<T>::retrieve(lua_State* l, int index, CheckStrenght check) {
290 StackCheck s(l);
292 if(check != DontCheck) {
293 if(!lua_getmetatable(l,index)) {
294 if(check == AssertOk)
295 luaL_error(l, "Mismatch, got object of unknown type expecting %s",
296 Wrapper<T>::class_name());
297 return NULL;
299 GenericWrapper<T>::push_meta_table(l);
301 if(!lua_rawequal(l, -2, -1)) {
302 if(check == AssertOk) {
303 if(lua_istable(l, -2)) {
304 lua_getfield(l, -2, ".type");
305 if(lua_isstring(l, -1))
306 luaL_error(l, "Mismatch, got object of type %s expecting %s",
307 wrap_cptr(lua_tostring(l,-1)), Wrapper<T>::class_name());
309 lua_pop(l,2);
310 luaL_error(l, "Mismatch, got object of unknown type expecting %s",
311 Wrapper<T>::class_name());
313 lua_pop(l,2);
314 return NULL;
316 lua_pop(l,2);
319 T** data = reinterpret_cast<T**>(
320 lua_touserdata(l, index));
321 return data ? *data : NULL;
324 template<typename T>
325 int GenericWrapper<T>::deallocate(lua_State* l) {
326 StackCheck s(l, -1);
328 T* data = retrieve(l);
329 lua_pop(l, 1);
330 delete data;
331 return 0;
334 template<typename T>
335 void GenericWrapper<T>::allocate(lua_State* l, T* x) {
336 StackCheck s(l, 1);
338 // create userdata
339 T** data = reinterpret_cast<T**>(
340 lua_newuserdata(l, sizeof(T*)));
341 *data = x;
343 // set metatable
344 push_meta_table(l);
345 lua_setmetatable(l, -2);
348 template<typename T>
349 void GenericWrapper<T>::create_prototype(lua_State* l, const char* prototype_name) {
350 StackCheck s(l);
352 lua_newtable(l); // factory class
354 lua_newtable(l); // metatable
355 lua_pushcfunction(l, &constructor_wrapper);
356 lua_setfield(l, -2, "__call");
357 lua_setmetatable(l, -2);
359 lua_newtable(l); // object metatable
360 // add gc metamethod
361 lua_pushcfunction(l, &deallocate);
362 lua_setfield(l, -2, "__gc");
364 // add index metamethod
365 lua_pushcfunction(l, &object_meta_index_event);
366 lua_setfield(l, -2, "__index");
368 // add newindex metamethod
369 lua_pushcfunction(l, &object_meta_newindex_event);
370 lua_setfield(l, -2, "__newindex");
372 lua_newtable(l);
373 lua_setfield(l, -2, ".methods");
375 lua_newtable(l);
376 lua_setfield(l, -2, ".get");
378 lua_newtable(l);
379 lua_setfield(l, -2, ".set");
381 lua_pushstring(l, prototype_name);
382 lua_setfield(l, -2, ".type");
384 Wrapper<T>::create_index_table(l);
385 lua_setfield(l, -2, "object_meta_table");
387 lua_setglobal(l, prototype_name);
390 template<typename T>
391 int GenericWrapper<T>::constructor_wrapper(lua_State* l) {
392 lua_remove(l, 1);
393 return Wrapper<T>::constructor(l);
396 template<typename T>
397 void GenericWrapper<T>::push_meta_table(lua_State* l) {
398 StackCheck s(l, 1);
400 lua_getglobal(l, Wrapper<T>::class_name());
401 lua_pushstring(l, "object_meta_table");
402 lua_rawget(l,-2);
403 lua_remove(l,-2);
406 //END GenericWrapper-----------------------------------------------------------
408 //BEGIN GenericWrapperByValue---------------------------------------------------------
410 template <typename T>
411 class GenericWrapperByValue : public GenericWrapperBase {
412 public:
414 static void register_class(lua_State* l);
417 * Retrieve a wrapped object on the stack.
419 static T* retrieve(lua_State* l, int index = -1, CheckStrenght check = Check);
422 * Destroy a wrapped object of type T.
424 static int deallocate(lua_State* l);
427 * Wrap an object of type T in a Lua userdatum.
428 * Lua takes ownership of the object, so that it is
429 * automatically disposed by the Lua garbage collector.
431 static void allocate(lua_State* l, const T x);
433 static void create(lua_State* l);
434 template<typename A1>
435 static void create(lua_State* l, const A1&);
436 template<typename A1, typename A2>
437 static void create(lua_State* l, const A1&, const A2&);
438 template<typename A1, typename A2, typename A3>
439 static void create(lua_State* l, const A1&, const A2&, const A3&);
440 template<typename A1, typename A2, typename A3, typename A4>
441 static void create(lua_State* l, const A1&, const A2&, const A3&, const A4&);
442 template<typename A1, typename A2, typename A3, typename A4, typename A5>
443 static void create(lua_State* l, const A1&, const A2&, const A3&, const A4&, const A5&);
446 * Create the factory class and static metatable.
448 static void create_prototype(lua_State* l, const char* prototype_name);
451 * Calls the Wrapper&lt;T&gt; constructor
453 static int constructor_wrapper(lua_State* l);
456 * Pushes this object's meta table.
458 static void push_meta_table(lua_State* l);
461 template<typename T>
462 void GenericWrapperByValue<T>::register_class(lua_State* l) {
463 create_prototype(l, Wrapper<T>::class_name());
466 template<typename T>
467 T* GenericWrapperByValue<T>::retrieve(lua_State* l, int index, CheckStrenght check) {
468 StackCheck s(l);
470 if(check != DontCheck) {
471 if(!lua_getmetatable(l,index)) {
472 if(check == AssertOk)
473 luaL_error(l, "Mismatch, got object of unknown type expecting %s",
474 Wrapper<T>::class_name());
475 return NULL;
477 GenericWrapperByValue<T>::push_meta_table(l);
479 if(!lua_rawequal(l, -2, -1)) {
480 if(check == AssertOk) {
481 if(lua_istable(l, -2)) {
482 lua_getfield(l, -2, ".type");
483 if(lua_isstring(l, -1))
484 luaL_error(l, "Mismatch, got object of type %s expecting %s",
485 wrap_cptr(lua_tostring(l,-1)), Wrapper<T>::class_name());
487 lua_pop(l,2);
488 luaL_error(l, "Mismatch, got object of unknown type expecting %s",
489 Wrapper<T>::class_name());
491 lua_pop(l,2);
492 return NULL;
494 lua_pop(l,2);
497 T* data = reinterpret_cast<T*>(
498 lua_touserdata(l, index));
499 return data;
502 template<typename T>
503 int GenericWrapperByValue<T>::deallocate(lua_State* l) {
504 StackCheck s(l, -1);
506 T* data = retrieve(l);
507 lua_pop(l, 1);
508 data->~T(); //placement delete
509 return 0;
512 template<typename T>
513 void GenericWrapperByValue<T>::allocate(lua_State* l, T x) {
514 StackCheck s(l, 1);
516 // create userdata
517 T* data = reinterpret_cast<T*>(
518 lua_newuserdata(l, sizeof(T)));
519 new(data) T(x); //placement new
521 StackCheck check(l);
523 // set metatable
524 push_meta_table(l);
525 lua_setmetatable(l, -2);
528 template<typename T>
529 void GenericWrapperByValue<T>::create(lua_State* l) {
530 StackCheck s(l, 1);
532 T* data = reinterpret_cast<T*>(lua_newuserdata(l, sizeof(T)));
533 new(data) T(); //placement new
534 push_meta_table(l);
535 lua_setmetatable(l, -2);
538 template<typename T>
539 template<typename A1>
540 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1) {
541 StackCheck s(l, 1);
543 T* data = reinterpret_cast<T*>(lua_newuserdata(l, sizeof(T)));
544 new(data) T(a1); //placement new
545 push_meta_table(l);
546 lua_setmetatable(l, -2);
549 template<typename T>
550 template<typename A1, typename A2>
551 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1, const A2& a2) {
552 StackCheck s(l, 1);
554 T* data = reinterpret_cast<T*>(lua_newuserdata(l, sizeof(T)));
555 new(data) T(a1, a2); //placement new
556 push_meta_table(l);
557 lua_setmetatable(l, -2);
560 template<typename T>
561 template<typename A1, typename A2, typename A3>
562 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1, const A2& a2, const A3& a3) {
563 StackCheck s(l, 1);
565 T* data = reinterpret_cast<T*>(lua_newuserdata(l, sizeof(T)));
566 new(data) T(a1, a2, a3); //placement new
567 push_meta_table(l);
568 lua_setmetatable(l, -2);
571 template<typename T>
572 template<typename A1, typename A2, typename A3, typename A4>
573 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1, const A2& a2,
574 const A3& a3, const A4& a4) {
575 StackCheck s(l, 1);
577 T* data = reinterpret_cast<T*>(lua_newuserdata(l, sizeof(T)));
578 new(data) T(a1, a2, a3, a4); //placement new
579 push_meta_table(l);
580 lua_setmetatable(l, -2);
583 template<typename T>
584 template<typename A1, typename A2, typename A3, typename A4, typename A5>
585 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1, const A2& a2, const A3& a3,
586 const A4& a4, const A5& a5) {
587 StackCheck s(l, 1);
589 T* data = reinterpret_cast<T*>(lua_newuserdata(l, sizeof(T)));
590 new(data) T(a1, a2, a3, a4, a5); //placement new
591 push_meta_table(l);
592 lua_setmetatable(l, -2);
595 template<typename T>
596 void GenericWrapperByValue<T>::create_prototype(lua_State* l, const char* prototype_name) {
597 StackCheck s(l);
599 lua_newtable(l); // factory class
601 lua_newtable(l); // metatable
602 lua_pushcfunction(l, &constructor_wrapper);
603 lua_setfield(l, -2, "__call");
604 lua_setmetatable(l, -2);
606 lua_newtable(l); // object metatable
607 // add gc metamethod
608 lua_pushcfunction(l, &deallocate);
609 lua_setfield(l, -2, "__gc");
611 // add index metamethod
612 lua_pushcfunction(l, &object_meta_index_event);
613 lua_setfield(l, -2, "__index");
615 // add newindex metamethod
616 lua_pushcfunction(l, &object_meta_newindex_event);
617 lua_setfield(l, -2, "__newindex");
619 lua_newtable(l);
620 lua_setfield(l, -2, ".methods");
622 lua_newtable(l);
623 lua_setfield(l, -2, ".get");
625 lua_newtable(l);
626 lua_setfield(l, -2, ".set");
628 lua_pushstring(l, prototype_name);
629 lua_setfield(l, -2, ".type");
631 Wrapper<T>::create_index_table(l);
632 lua_setfield(l, -2, "object_meta_table");
634 lua_setglobal(l, prototype_name);
637 template<typename T>
638 int GenericWrapperByValue<T>::constructor_wrapper(lua_State* l) {
639 lua_remove(l, 1);
640 return Wrapper<T>::constructor(l);
643 template<typename T>
644 void GenericWrapperByValue<T>::push_meta_table(lua_State* l) {
645 StackCheck s(l, 1);
647 lua_getglobal(l, Wrapper<T>::class_name());
648 lua_pushstring(l, "object_meta_table");
649 lua_rawget(l,-2);
650 lua_remove(l,-2);
653 //END GenericWrapperByValue-----------------------------------------------------------
656 template<typename T>
657 class Comparable {
658 public:
659 static void register_in_index_table(lua_State* l);
660 static int eq_event(lua_State* l);
663 template<typename T>
664 void Comparable<T>::register_in_index_table(lua_State* l) {
665 Wrapper<T>::set_meta_method(l, &eq_event, "__eq");
668 template<typename T>
669 int Comparable<T>::eq_event(lua_State* l) {
670 int n = lua_gettop(l);
671 if(n != 2)
672 luaL_error(l, "Wrong argument count %d for __eq", n);
673 T *p1 = Wrapper<T>::retrieve(l, 1, AssertOk);
674 T *p2 = Wrapper<T>::retrieve(l, 2, AssertOk);
675 lua_pop(l, n);
676 lua_pushboolean(l, *p1 == *p2);
677 return 1;
680 template<typename T>
681 class Summable {
682 public:
683 static void register_in_index_table(lua_State* l);
684 static int add_event(lua_State* l);
685 static int sub_event(lua_State* l);
686 static int unm_event(lua_State* l);
689 template<typename T>
690 void Summable<T>::register_in_index_table(lua_State* l) {
691 Wrapper<T>::set_meta_method(l, &add_event, "__add");
692 Wrapper<T>::set_meta_method(l, &sub_event, "__sub");
693 Wrapper<T>::set_meta_method(l, &unm_event, "__unm");
696 template<typename T>
697 int Summable<T>::add_event(lua_State* l) {
698 int n = lua_gettop(l);
699 if(n != 2)
700 luaL_error(l, "Wrong argument count %d for __add", n);
701 T *p1 = Wrapper<T>::retrieve(l, 1, AssertOk);
702 T *p2 = Wrapper<T>::retrieve(l, 2, AssertOk);
703 lua_pop(l, n);
705 Wrapper<T>::allocate(l, new T(*p1 + *p2));
707 return 1;
710 template<typename T>
711 int Summable<T>::sub_event(lua_State* l) {
712 int n = lua_gettop(l);
713 if(n != 2)
714 luaL_error(l, "Wrong argument count %d for __sub", n);
715 T *p1 = Wrapper<T>::retrieve(l, 1, AssertOk);
716 T *p2 = Wrapper<T>::retrieve(l, 2, AssertOk);
717 lua_pop(l, n);
719 Wrapper<T>::allocate(l, new T(*p1 - *p2));
721 return 1;
724 template<typename T>
725 int Summable<T>::unm_event(lua_State* l) {
726 int n = lua_gettop(l);
728 /* for some strange reason unm gets 2 copies of the same argument */
729 if(n != 2)
730 luaL_error(l, "Wrong argument count %d for __unm", n);
731 T *p1 = Wrapper<T>::retrieve(l, 1, AssertOk);
732 lua_pop(l, n);
734 Wrapper<T>::allocate(l, new T(-*p1));
736 return 1;
739 } //end namespace LuaApi
742 #endif //LUAAPI__GENERICWRAPPER_H