Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/tolua/tolua_event.c @ 3127

Last change on this file since 3127 was 3127, checked in by rgrieder, 15 years ago

Update to tolua 1.0.93

  • Property svn:eol-style set to native
File size: 13.6 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        /* copying code from do_operator here to return false when no operator is found */
375        if (lua_isuserdata(L,1))
376        {
377                /* Try metatables */
378                lua_pushvalue(L,1);                     /* stack: op1 op2 */
379                while (lua_getmetatable(L,-1))
380                {                                       /* stack: op1 op2 op1 mt */
381                        lua_remove(L,-2);                      /* stack: op1 op2 mt */
382                        lua_pushstring(L,".eq");                  /* stack: op1 op2 mt key */
383                        lua_rawget(L,-2);                      /* stack: obj key mt func */
384                        if (lua_isfunction(L,-1))
385                        {
386                                lua_pushvalue(L,1);
387                                lua_pushvalue(L,2);
388                                lua_call(L,2,1);
389                                return 1;
390                        }
391                        lua_settop(L,3);
392                }
393        }
394
395        lua_settop(L, 3);
396        lua_pushboolean(L, 0);
397        return 1;
398}
399
400/*
401static int class_gc_event (lua_State* L)
402{
403        void* u = *((void**)lua_touserdata(L,1));
404        fprintf(stderr, "collecting: looking at %p\n", u);
405        lua_pushstring(L,"tolua_gc");
406        lua_rawget(L,LUA_REGISTRYINDEX);
407        lua_pushlightuserdata(L,u);
408        lua_rawget(L,-2);
409        if (lua_isfunction(L,-1))
410        {
411                lua_pushvalue(L,1);
412                lua_call(L,1,0);
413                lua_pushlightuserdata(L,u);
414                lua_pushnil(L);
415                lua_rawset(L,-3);
416        }
417        lua_pop(L,2);
418        return 0;
419}
420*/
421TOLUA_API int class_gc_event (lua_State* L)
422{
423        void* u = *((void**)lua_touserdata(L,1));
424        int top;
425        /*fprintf(stderr, "collecting: looking at %p\n", u);*/
426        /*
427        lua_pushstring(L,"tolua_gc");
428        lua_rawget(L,LUA_REGISTRYINDEX);
429        */
430        lua_pushvalue(L, lua_upvalueindex(1));
431        lua_pushlightuserdata(L,u);
432        lua_rawget(L,-2);            /* stack: gc umt    */
433        lua_getmetatable(L,1);       /* stack: gc umt mt */
434        /*fprintf(stderr, "checking type\n");*/
435        top = lua_gettop(L);
436        if (tolua_fast_isa(L,top,top-1, lua_upvalueindex(2))) /* make sure we collect correct type */
437        {
438                /*fprintf(stderr, "Found type!\n");*/
439                /* get gc function */
440                lua_pushliteral(L,".collector");
441                lua_rawget(L,-2);           /* stack: gc umt mt collector */
442                if (lua_isfunction(L,-1)) {
443                        /*fprintf(stderr, "Found .collector!\n");*/
444                }
445                else {
446                        lua_pop(L,1);
447                        /*fprintf(stderr, "Using default cleanup\n");*/
448                        lua_pushcfunction(L,tolua_default_collect);
449                }
450
451                lua_pushvalue(L,1);         /* stack: gc umt mt collector u */
452                lua_call(L,1,0);
453
454                lua_pushlightuserdata(L,u); /* stack: gc umt mt u */
455                lua_pushnil(L);             /* stack: gc umt mt u nil */
456                lua_rawset(L,-5);           /* stack: gc umt mt */
457        }
458        lua_pop(L,3);
459        return 0;
460}
461
462
463/* Register module events
464        * It expects the metatable on the top of the stack
465*/
466TOLUA_API void tolua_moduleevents (lua_State* L)
467{
468        lua_pushstring(L,"__index");
469        lua_pushcfunction(L,module_index_event);
470        lua_rawset(L,-3);
471        lua_pushstring(L,"__newindex");
472        lua_pushcfunction(L,module_newindex_event);
473        lua_rawset(L,-3);
474}
475
476/* Check if the object on the top has a module metatable
477*/
478TOLUA_API int tolua_ismodulemetatable (lua_State* L)
479{
480        int r = 0;
481        if (lua_getmetatable(L,-1))
482        {
483                lua_pushstring(L,"__index");
484                lua_rawget(L,-2);
485                r = (lua_tocfunction(L,-1) == module_index_event);
486                lua_pop(L,2);
487        }
488        return r;
489}
490
491/* Register class events
492        * It expects the metatable on the top of the stack
493*/
494TOLUA_API void tolua_classevents (lua_State* L)
495{
496        lua_pushstring(L,"__index");
497        lua_pushcfunction(L,class_index_event);
498        lua_rawset(L,-3);
499        lua_pushstring(L,"__newindex");
500        lua_pushcfunction(L,class_newindex_event);
501        lua_rawset(L,-3);
502
503        lua_pushstring(L,"__add");
504        lua_pushcfunction(L,class_add_event);
505        lua_rawset(L,-3);
506        lua_pushstring(L,"__sub");
507        lua_pushcfunction(L,class_sub_event);
508        lua_rawset(L,-3);
509        lua_pushstring(L,"__mul");
510        lua_pushcfunction(L,class_mul_event);
511        lua_rawset(L,-3);
512        lua_pushstring(L,"__div");
513        lua_pushcfunction(L,class_div_event);
514        lua_rawset(L,-3);
515
516        lua_pushstring(L,"__lt");
517        lua_pushcfunction(L,class_lt_event);
518        lua_rawset(L,-3);
519        lua_pushstring(L,"__le");
520        lua_pushcfunction(L,class_le_event);
521        lua_rawset(L,-3);
522        lua_pushstring(L,"__eq");
523        lua_pushcfunction(L,class_eq_event);
524        lua_rawset(L,-3);
525
526        lua_pushstring(L,"__call");
527        lua_pushcfunction(L,class_call_event);
528        lua_rawset(L,-3);
529
530        lua_pushstring(L,"__gc");
531        lua_pushstring(L, "tolua_gc_event");
532        lua_rawget(L, LUA_REGISTRYINDEX);
533        /*lua_pushcfunction(L,class_gc_event);*/
534        lua_rawset(L,-3);
535}
536
Note: See TracBrowser for help on using the repository browser.