Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/tolua/tolua_event.c @ 1494

Last change on this file since 1494 was 1494, checked in by rgrieder, 16 years ago
  • set the svn:eol-style property to all files so, that where ever you check out, you'll get the right line endings (had to change every file with mixed endings to windows in order to set the property)
  • Property svn:eol-style set to native
File size: 12.9 KB
Line 
1/* tolua: event functions
2** Support code for Lua bindings.
3** Written by Waldemar Celes
4** TeCGraf/PUC-Rio
5** Apr 2003
6** $Id: $
7*/
8
9/* This code is free software; you can redistribute it and/or modify it.
10** The software provided hereunder is on an "as is" basis, and
11** the author has no obligation to provide maintenance, support, updates,
12** enhancements, or modifications.
13*/
14
15#include <stdio.h>
16
17#include "tolua++.h"
18
19/* Store at ubox
20        * It stores, creating the corresponding table if needed,
21        * the pair key/value in the corresponding ubox table
22*/
23static void storeatubox (lua_State* L, int lo)
24{
25        #ifdef LUA_VERSION_NUM
26                lua_getfenv(L, lo);
27                if (lua_rawequal(L, -1, TOLUA_NOPEER)) {
28                        lua_pop(L, 1);
29                        lua_newtable(L);
30                        lua_pushvalue(L, -1);
31                        lua_setfenv(L, lo);     /* stack: k,v,table  */
32                };
33                lua_insert(L, -3);
34                lua_settable(L, -3); /* on lua 5.1, we trade the "tolua_peers" lookup for a settable call */
35                lua_pop(L, 1);
36        #else
37         /* stack: key value (to be stored) */
38                lua_pushstring(L,"tolua_peers");
39                lua_rawget(L,LUA_REGISTRYINDEX);        /* stack: k v ubox */
40                lua_pushvalue(L,lo);
41                lua_rawget(L,-2);                       /* stack: k v ubox ubox[u] */
42                if (!lua_istable(L,-1))
43                {
44                        lua_pop(L,1);                          /* stack: k v ubox */
45                        lua_newtable(L);                       /* stack: k v ubox table */
46                        lua_pushvalue(L,1);
47                        lua_pushvalue(L,-2);                   /* stack: k v ubox table u table */
48                        lua_rawset(L,-4);                      /* stack: k v ubox ubox[u]=table */
49                }
50                lua_insert(L,-4);                       /* put table before k */
51                lua_pop(L,1);                           /* pop ubox */
52                lua_rawset(L,-3);                       /* store at table */
53                lua_pop(L,1);                           /* pop ubox[u] */
54        #endif
55}
56
57/* Module index function
58*/
59static int module_index_event (lua_State* L)
60{
61        lua_pushstring(L,".get");
62        lua_rawget(L,-3);
63        if (lua_istable(L,-1))
64        {
65                lua_pushvalue(L,2);  /* key */
66                lua_rawget(L,-2);
67                if (lua_iscfunction(L,-1))
68                {
69                        lua_call(L,0,1);
70                        return 1;
71                }
72                else if (lua_istable(L,-1))
73                        return 1;
74        }
75        /* call old index meta event */
76        if (lua_getmetatable(L,1))
77        {
78                lua_pushstring(L,"__index");
79                lua_rawget(L,-2);
80                lua_pushvalue(L,1);
81                lua_pushvalue(L,2);
82                if (lua_isfunction(L,-1))
83                {
84                        lua_call(L,2,1);
85                        return 1;
86                }
87                else if (lua_istable(L,-1))
88                {
89                        lua_gettable(L,-3);
90                        return 1;
91                }
92        }
93        lua_pushnil(L);
94        return 1;
95}
96
97/* Module newindex function
98*/
99static int module_newindex_event (lua_State* L)
100{
101        lua_pushstring(L,".set");
102        lua_rawget(L,-4);
103        if (lua_istable(L,-1))
104        {
105                lua_pushvalue(L,2);  /* key */
106                lua_rawget(L,-2);
107                if (lua_iscfunction(L,-1))
108                {
109                        lua_pushvalue(L,1); /* only to be compatible with non-static vars */
110                        lua_pushvalue(L,3); /* value */
111                        lua_call(L,2,0);
112                        return 0;
113                }
114        }
115        /* call old newindex meta event */
116        if (lua_getmetatable(L,1) && lua_getmetatable(L,-1))
117        {
118                lua_pushstring(L,"__newindex");
119                lua_rawget(L,-2);
120                if (lua_isfunction(L,-1))
121                {
122                 lua_pushvalue(L,1);
123                 lua_pushvalue(L,2);
124                 lua_pushvalue(L,3);
125                        lua_call(L,3,0);
126                }
127        }
128        lua_settop(L,3);
129        lua_rawset(L,-3);
130        return 0;
131}
132
133/* Class index function
134        * If the object is a userdata (ie, an object), it searches the field in
135        * the alternative table stored in the corresponding "ubox" table.
136*/
137static int class_index_event (lua_State* L)
138{
139 int t = lua_type(L,1);
140        if (t == LUA_TUSERDATA)
141        {
142                /* Access alternative table */
143                #ifdef LUA_VERSION_NUM /* new macro on version 5.1 */
144                lua_getfenv(L,1);
145                if (!lua_rawequal(L, -1, TOLUA_NOPEER)) {
146                        lua_pushvalue(L, 2); /* key */
147                        lua_gettable(L, -2); /* on lua 5.1, we trade the "tolua_peers" lookup for a gettable call */
148                        if (!lua_isnil(L, -1))
149                                return 1;
150                };
151                #else
152                lua_pushstring(L,"tolua_peers");
153                lua_rawget(L,LUA_REGISTRYINDEX);        /* stack: obj key ubox */
154                lua_pushvalue(L,1);
155                lua_rawget(L,-2);                       /* stack: obj key ubox ubox[u] */
156                if (lua_istable(L,-1))
157                {
158                        lua_pushvalue(L,2);  /* key */
159                        lua_rawget(L,-2);                      /* stack: obj key ubox ubox[u] value */
160                        if (!lua_isnil(L,-1))
161                                return 1;
162                }
163                #endif
164                lua_settop(L,2);                        /* stack: obj key */
165                /* Try metatables */
166                lua_pushvalue(L,1);                     /* stack: obj key obj */
167                while (lua_getmetatable(L,-1))
168                {                                       /* stack: obj key obj mt */
169                        lua_remove(L,-2);                      /* stack: obj key mt */
170                        if (lua_isnumber(L,2))                 /* check if key is a numeric value */
171                        {
172                                /* try operator[] */
173                                lua_pushstring(L,".geti");
174                                lua_rawget(L,-2);                      /* stack: obj key mt func */
175                                if (lua_isfunction(L,-1))
176                                {
177                                        lua_pushvalue(L,1);
178                                        lua_pushvalue(L,2);
179                                        lua_call(L,2,1);
180                                        return 1;
181                                }
182                        }
183                        else
184                        {
185                         lua_pushvalue(L,2);                    /* stack: obj key mt key */
186                                lua_rawget(L,-2);                      /* stack: obj key mt value */
187                                if (!lua_isnil(L,-1))
188                                        return 1;
189                                else
190                                        lua_pop(L,1);
191                                /* try C/C++ variable */
192                                lua_pushstring(L,".get");
193                                lua_rawget(L,-2);                      /* stack: obj key mt tget */
194                                if (lua_istable(L,-1))
195                                {
196                                        lua_pushvalue(L,2);
197                                        lua_rawget(L,-2);                      /* stack: obj key mt value */
198                                        if (lua_iscfunction(L,-1))
199                                        {
200                                                lua_pushvalue(L,1);
201                                                lua_pushvalue(L,2);
202                                                lua_call(L,2,1);
203                                                return 1;
204                                        }
205                                        else if (lua_istable(L,-1))
206                                        {
207                                                /* deal with array: create table to be returned and cache it in ubox */
208                                                void* u = *((void**)lua_touserdata(L,1));
209                                                lua_newtable(L);                /* stack: obj key mt value table */
210                                                lua_pushstring(L,".self");
211                                                lua_pushlightuserdata(L,u);
212                                                lua_rawset(L,-3);               /* store usertype in ".self" */
213                                                lua_insert(L,-2);               /* stack: obj key mt table value */
214                                                lua_setmetatable(L,-2);         /* set stored value as metatable */
215                                                lua_pushvalue(L,-1);            /* stack: obj key met table table */
216                                                lua_pushvalue(L,2);             /* stack: obj key mt table table key */
217                                                lua_insert(L,-2);               /*  stack: obj key mt table key table */
218                                                storeatubox(L,1);               /* stack: obj key mt table */
219                                                return 1;
220                                        }
221                                }
222                        }
223                        lua_settop(L,3);
224                }
225                lua_pushnil(L);
226                return 1;
227        }
228        else if (t== LUA_TTABLE)
229        {
230                module_index_event(L);
231                return 1;
232        }
233        lua_pushnil(L);
234        return 1;
235}
236
237/* Newindex function
238        * It first searches for a C/C++ varaible to be set.
239        * Then, it either stores it in the alternative ubox table (in the case it is
240        * an object) or in the own table (that represents the class or module).
241*/
242static int class_newindex_event (lua_State* L)
243{
244 int t = lua_type(L,1);
245        if (t == LUA_TUSERDATA)
246        {
247         /* Try accessing a C/C++ variable to be set */
248                lua_getmetatable(L,1);
249                while (lua_istable(L,-1))                /* stack: t k v mt */
250                {
251                        if (lua_isnumber(L,2))                 /* check if key is a numeric value */
252                        {
253                                /* try operator[] */
254                                lua_pushstring(L,".seti");
255                                lua_rawget(L,-2);                      /* stack: obj key mt func */
256                                if (lua_isfunction(L,-1))
257                                {
258                                        lua_pushvalue(L,1);
259                                        lua_pushvalue(L,2);
260                                        lua_pushvalue(L,3);
261                                        lua_call(L,3,0);
262                                        return 0;
263                                }
264                        }
265                        else
266                        {
267                                lua_pushstring(L,".set");
268                                lua_rawget(L,-2);                      /* stack: t k v mt tset */
269                                if (lua_istable(L,-1))
270                                {
271                                        lua_pushvalue(L,2);
272                                        lua_rawget(L,-2);                     /* stack: t k v mt tset func */
273                                        if (lua_iscfunction(L,-1))
274                                        {
275                                                lua_pushvalue(L,1);
276                                                lua_pushvalue(L,3);
277                                                lua_call(L,2,0);
278                                                return 0;
279                                        }
280                                        lua_pop(L,1);                          /* stack: t k v mt tset */
281                                }
282                                lua_pop(L,1);                           /* stack: t k v mt */
283                                if (!lua_getmetatable(L,-1))            /* stack: t k v mt mt */
284                                        lua_pushnil(L);
285                                lua_remove(L,-2);                       /* stack: t k v mt */
286                        }
287                }
288         lua_settop(L,3);                          /* stack: t k v */
289
290                /* then, store as a new field */
291                storeatubox(L,1);
292        }
293        else if (t== LUA_TTABLE)
294        {
295                module_newindex_event(L);
296        }
297        return 0;
298}
299
300static int class_call_event(lua_State* L) {
301
302        if (lua_istable(L, 1)) {
303                lua_pushstring(L, ".call");
304                lua_rawget(L, 1);
305                if (lua_isfunction(L, -1)) {
306
307                        lua_insert(L, 1);
308                        lua_call(L, lua_gettop(L)-1, 1);
309
310                        return 1;
311                };
312        };
313        tolua_error(L,"Attempt to call a non-callable object.",NULL);
314        return 0;
315};
316
317static int do_operator (lua_State* L, const char* op)
318{
319        if (lua_isuserdata(L,1))
320        {
321                /* Try metatables */
322                lua_pushvalue(L,1);                     /* stack: op1 op2 */
323                while (lua_getmetatable(L,-1))
324                {                                       /* stack: op1 op2 op1 mt */
325                        lua_remove(L,-2);                      /* stack: op1 op2 mt */
326                        lua_pushstring(L,op);                  /* stack: op1 op2 mt key */
327                        lua_rawget(L,-2);                      /* stack: obj key mt func */
328                        if (lua_isfunction(L,-1))
329                        {
330                                lua_pushvalue(L,1);
331                                lua_pushvalue(L,2);
332                                lua_call(L,2,1);
333                                return 1;
334                        }
335                        lua_settop(L,3);
336                }
337        }
338        tolua_error(L,"Attempt to perform operation on an invalid operand",NULL);
339        return 0;
340}
341
342static int class_add_event (lua_State* L)
343{
344        return do_operator(L,".add");
345}
346
347static int class_sub_event (lua_State* L)
348{
349        return do_operator(L,".sub");
350}
351
352static int class_mul_event (lua_State* L)
353{
354        return do_operator(L,".mul");
355}
356
357static int class_div_event (lua_State* L)
358{
359        return do_operator(L,".div");
360}
361
362static int class_lt_event (lua_State* L)
363{
364        return do_operator(L,".lt");
365}
366
367static int class_le_event (lua_State* L)
368{
369        return do_operator(L,".le");
370}
371
372static int class_eq_event (lua_State* L)
373{
374        return do_operator(L,".eq");
375}
376
377/*
378static int class_gc_event (lua_State* L)
379{
380        void* u = *((void**)lua_touserdata(L,1));
381        fprintf(stderr, "collecting: looking at %p\n", u);
382        lua_pushstring(L,"tolua_gc");
383        lua_rawget(L,LUA_REGISTRYINDEX);
384        lua_pushlightuserdata(L,u);
385        lua_rawget(L,-2);
386        if (lua_isfunction(L,-1))
387        {
388                lua_pushvalue(L,1);
389                lua_call(L,1,0);
390                lua_pushlightuserdata(L,u);
391                lua_pushnil(L);
392                lua_rawset(L,-3);
393        }
394        lua_pop(L,2);
395        return 0;
396}
397*/
398TOLUA_API int class_gc_event (lua_State* L)
399{
400        void* u = *((void**)lua_touserdata(L,1));
401        int top;
402        /*fprintf(stderr, "collecting: looking at %p\n", u);*/
403        /*
404        lua_pushstring(L,"tolua_gc");
405        lua_rawget(L,LUA_REGISTRYINDEX);
406        */
407        lua_pushvalue(L, lua_upvalueindex(1));
408        lua_pushlightuserdata(L,u);
409        lua_rawget(L,-2);            /* stack: gc umt    */
410        lua_getmetatable(L,1);       /* stack: gc umt mt */
411        /*fprintf(stderr, "checking type\n");*/
412        top = lua_gettop(L);
413        if (tolua_fast_isa(L,top,top-1, lua_upvalueindex(2))) /* make sure we collect correct type */
414        {
415                /*fprintf(stderr, "Found type!\n");*/
416                /* get gc function */
417                lua_pushliteral(L,".collector");
418                lua_rawget(L,-2);           /* stack: gc umt mt collector */
419                if (lua_isfunction(L,-1)) {
420                        /*fprintf(stderr, "Found .collector!\n");*/
421                }
422                else {
423                        lua_pop(L,1);
424                        /*fprintf(stderr, "Using default cleanup\n");*/
425                        lua_pushcfunction(L,tolua_default_collect);
426                }
427
428                lua_pushvalue(L,1);         /* stack: gc umt mt collector u */
429                lua_call(L,1,0);
430
431                lua_pushlightuserdata(L,u); /* stack: gc umt mt u */
432                lua_pushnil(L);             /* stack: gc umt mt u nil */
433                lua_rawset(L,-5);           /* stack: gc umt mt */
434        }
435        lua_pop(L,3);
436        return 0;
437}
438
439
440/* Register module events
441        * It expects the metatable on the top of the stack
442*/
443TOLUA_API void tolua_moduleevents (lua_State* L)
444{
445        lua_pushstring(L,"__index");
446        lua_pushcfunction(L,module_index_event);
447        lua_rawset(L,-3);
448        lua_pushstring(L,"__newindex");
449        lua_pushcfunction(L,module_newindex_event);
450        lua_rawset(L,-3);
451}
452
453/* Check if the object on the top has a module metatable
454*/
455TOLUA_API int tolua_ismodulemetatable (lua_State* L)
456{
457        int r = 0;
458        if (lua_getmetatable(L,-1))
459        {
460                lua_pushstring(L,"__index");
461                lua_rawget(L,-2);
462                r = (lua_tocfunction(L,-1) == module_index_event);
463                lua_pop(L,2);
464        }
465        return r;
466}
467
468/* Register class events
469        * It expects the metatable on the top of the stack
470*/
471TOLUA_API void tolua_classevents (lua_State* L)
472{
473        lua_pushstring(L,"__index");
474        lua_pushcfunction(L,class_index_event);
475        lua_rawset(L,-3);
476        lua_pushstring(L,"__newindex");
477        lua_pushcfunction(L,class_newindex_event);
478        lua_rawset(L,-3);
479
480        lua_pushstring(L,"__add");
481        lua_pushcfunction(L,class_add_event);
482        lua_rawset(L,-3);
483        lua_pushstring(L,"__sub");
484        lua_pushcfunction(L,class_sub_event);
485        lua_rawset(L,-3);
486        lua_pushstring(L,"__mul");
487        lua_pushcfunction(L,class_mul_event);
488        lua_rawset(L,-3);
489        lua_pushstring(L,"__div");
490        lua_pushcfunction(L,class_div_event);
491        lua_rawset(L,-3);
492
493        lua_pushstring(L,"__lt");
494        lua_pushcfunction(L,class_lt_event);
495        lua_rawset(L,-3);
496        lua_pushstring(L,"__le");
497        lua_pushcfunction(L,class_le_event);
498        lua_rawset(L,-3);
499        lua_pushstring(L,"__eq");
500        lua_pushcfunction(L,class_eq_event);
501        lua_rawset(L,-3);
502
503        lua_pushstring(L,"__call");
504        lua_pushcfunction(L,class_call_event);
505        lua_rawset(L,-3);
506
507        lua_pushstring(L,"__gc");
508        lua_pushstring(L, "tolua_gc_event");
509        lua_rawget(L, LUA_REGISTRYINDEX);
510        /*lua_pushcfunction(L,class_gc_event);*/
511        lua_rawset(L,-3);
512}
513
Note: See TracBrowser for help on using the repository browser.