1
/* tolua: event functions
2
** Support code for Lua bindings.
3
** Written by Waldemar Celes
6
** $Id: tolua_event.c 10334 2005-04-26 22:08:24Z vas $
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.
17
#include "tolua_event.h"
21
* It stores, creating the corresponding table if needed,
22
* the pair key/value in the corresponding peer table
24
static void storeatpeer (lua_State* L, int u)
26
/* stack: key value (to be stored) */
27
lua_pushstring(L,"tolua_peer");
28
lua_rawget(L,LUA_REGISTRYINDEX); /* stack: k v peer */
30
lua_rawget(L,-2); /* stack: k v peer peer[u] */
31
if (!lua_istable(L,-1))
33
lua_pop(L,1); /* stack: k v peer */
34
lua_newtable(L); /* stack: k v peer table */
36
lua_pushvalue(L,-2); /* stack: k v peer table u table */
37
lua_rawset(L,-4); /* stack: k v peer peer[u]=table */
39
lua_insert(L,-4); /* put table before k */
40
lua_pop(L,1); /* pop peer */
41
lua_rawset(L,-3); /* store at table */
42
lua_pop(L,1); /* pop peer[u] */
45
/* Module index function
47
static int module_index_event (lua_State* L)
49
lua_pushstring(L,".get");
51
if (lua_istable(L,-1))
53
lua_pushvalue(L,2); /* key */
55
if (lua_iscfunction(L,-1))
60
else if (lua_istable(L,-1))
63
/* call old index meta event */
64
if (lua_getmetatable(L,1))
66
lua_pushstring(L,"__index");
70
if (lua_isfunction(L,-1))
75
else if (lua_istable(L,-1))
85
/* Module newindex function
87
static int module_newindex_event (lua_State* L)
89
lua_pushstring(L,".set");
91
if (lua_istable(L,-1))
93
lua_pushvalue(L,2); /* key */
95
if (lua_iscfunction(L,-1))
97
lua_pushvalue(L,1); /* only to be compatible with non-static vars */
98
lua_pushvalue(L,3); /* value */
103
/* call old newindex meta event */
104
if (lua_getmetatable(L,1) && lua_getmetatable(L,-1))
106
lua_pushstring(L,"__newindex");
108
if (lua_isfunction(L,-1))
121
/* Class index function
122
* If the object is a userdata (ie, an object), it searches the field in
123
* the alternative table stored in the corresponding "peer" table.
125
static int class_index_event (lua_State* L)
127
int t = lua_type(L,1);
128
if (t == LUA_TUSERDATA)
130
/* Access alternative table */
131
lua_pushstring(L,"tolua_peer");
132
lua_rawget(L,LUA_REGISTRYINDEX); /* stack: obj key peer */
134
lua_rawget(L,-2); /* stack: obj key peer peer[u] */
135
if (lua_istable(L,-1))
137
lua_pushvalue(L,2); /* key */
138
lua_rawget(L,-2); /* stack: obj key peer peer[u] value */
139
if (!lua_isnil(L,-1))
142
lua_settop(L,2); /* stack: obj key */
144
lua_pushvalue(L,1); /* stack: obj key obj */
145
while (lua_getmetatable(L,-1))
146
{ /* stack: obj key obj mt */
147
lua_remove(L,-2); /* stack: obj key mt */
148
if (lua_isnumber(L,2)) /* check if key is a numeric value */
151
lua_pushstring(L,".geti");
152
lua_rawget(L,-2); /* stack: obj key mt func */
153
if (lua_isfunction(L,-1))
163
lua_pushvalue(L,2); /* stack: obj key mt key */
164
lua_rawget(L,-2); /* stack: obj key mt value */
165
if (!lua_isnil(L,-1))
169
/* try C/C++ variable */
170
lua_pushstring(L,".get");
171
lua_rawget(L,-2); /* stack: obj key mt tget */
172
if (lua_istable(L,-1))
175
lua_rawget(L,-2); /* stack: obj key mt value */
176
if (lua_iscfunction(L,-1))
183
else if (lua_istable(L,-1))
185
/* deal with array: create table to be returned and cache it in peer */
186
void* u = *((void**)lua_touserdata(L,1));
187
lua_newtable(L); /* stack: obj key mt value table */
188
lua_pushstring(L,".self");
189
lua_pushlightuserdata(L,u);
190
lua_rawset(L,-3); /* store usertype in ".self" */
191
lua_insert(L,-2); /* stack: obj key mt table value */
192
lua_setmetatable(L,-2); /* set stored value as metatable */
193
lua_pushvalue(L,-1); /* stack: obj key met table table */
194
lua_pushvalue(L,2); /* stack: obj key mt table table key */
195
lua_insert(L,-2); /* stack: obj key mt table key table */
196
storeatpeer(L,1); /* stack: obj key mt table */
206
else if (t== LUA_TTABLE)
208
module_index_event(L);
216
* It first searches for a C/C++ varaible to be set.
217
* Then, it either stores it in the alternative peer table (in the case it is
218
* an object) or in the own table (that represents the class or module).
220
static int class_newindex_event (lua_State* L)
222
int t = lua_type(L,1);
223
if (t == LUA_TUSERDATA)
225
/* Try accessing a C/C++ variable to be set */
226
lua_getmetatable(L,1);
227
while (lua_istable(L,-1)) /* stack: t k v mt */
229
if (lua_isnumber(L,2)) /* check if key is a numeric value */
232
lua_pushstring(L,".seti");
233
lua_rawget(L,-2); /* stack: obj key mt func */
234
if (lua_isfunction(L,-1))
245
lua_pushstring(L,".set");
246
lua_rawget(L,-2); /* stack: t k v mt tset */
247
if (lua_istable(L,-1))
250
lua_rawget(L,-2); /* stack: t k v mt tset func */
251
if (lua_iscfunction(L,-1))
258
lua_pop(L,1); /* stack: t k v mt tset */
260
lua_pop(L,1); /* stack: t k v mt */
261
if (!lua_getmetatable(L,-1)) /* stack: t k v mt mt */
263
lua_remove(L,-2); /* stack: t k v mt */
266
lua_settop(L,3); /* stack: t k v */
268
/* then, store as a new field */
271
else if (t== LUA_TTABLE)
273
module_newindex_event(L);
278
static int do_operator (lua_State* L, const char* op)
280
if (lua_isuserdata(L,1))
283
lua_pushvalue(L,1); /* stack: op1 op2 */
284
while (lua_getmetatable(L,-1))
285
{ /* stack: op1 op2 op1 mt */
286
lua_remove(L,-2); /* stack: op1 op2 mt */
287
lua_pushstring(L,op); /* stack: op1 op2 mt key */
288
lua_rawget(L,-2); /* stack: obj key mt func */
289
if (lua_isfunction(L,-1))
299
tolua_error(L,"Attempt to perform operation on an invalid operand",NULL);
303
static int class_add_event (lua_State* L)
305
return do_operator(L,".add");
308
static int class_sub_event (lua_State* L)
310
return do_operator(L,".sub");
313
static int class_mul_event (lua_State* L)
315
return do_operator(L,".mul");
318
static int class_div_event (lua_State* L)
320
return do_operator(L,".div");
323
static int class_lt_event (lua_State* L)
325
return do_operator(L,".lt");
328
static int class_le_event (lua_State* L)
330
return do_operator(L,".le");
333
static int class_eq_event (lua_State* L)
335
return do_operator(L,".eq");
338
static int class_gc_event (lua_State* L)
340
void* u = *((void**)lua_touserdata(L,1));
341
lua_pushstring(L,"tolua_gc");
342
lua_rawget(L,LUA_REGISTRYINDEX);
343
lua_pushlightuserdata(L,u);
345
if (lua_isfunction(L,-1))
349
lua_pushlightuserdata(L,u);
357
/* Register module events
358
* It expects the metatable on the top of the stack
360
TOLUA_API void tolua_moduleevents (lua_State* L)
362
lua_pushstring(L,"__index");
363
lua_pushcfunction(L,module_index_event);
365
lua_pushstring(L,"__newindex");
366
lua_pushcfunction(L,module_newindex_event);
370
/* Check if the object on the top has a module metatable
372
TOLUA_API int tolua_ismodulemetatable (lua_State* L)
375
if (lua_getmetatable(L,-1))
377
lua_pushstring(L,"__index");
379
r = (lua_tocfunction(L,-1) == module_index_event);
385
/* Register class events
386
* It expects the metatable on the top of the stack
388
TOLUA_API void tolua_classevents (lua_State* L)
390
lua_pushstring(L,"__index");
391
lua_pushcfunction(L,class_index_event);
393
lua_pushstring(L,"__newindex");
394
lua_pushcfunction(L,class_newindex_event);
397
lua_pushstring(L,"__add");
398
lua_pushcfunction(L,class_add_event);
400
lua_pushstring(L,"__sub");
401
lua_pushcfunction(L,class_sub_event);
403
lua_pushstring(L,"__mul");
404
lua_pushcfunction(L,class_mul_event);
406
lua_pushstring(L,"__div");
407
lua_pushcfunction(L,class_div_event);
410
lua_pushstring(L,"__lt");
411
lua_pushcfunction(L,class_lt_event);
413
lua_pushstring(L,"__le");
414
lua_pushcfunction(L,class_le_event);
416
lua_pushstring(L,"__eq");
417
lua_pushcfunction(L,class_eq_event);
420
lua_pushstring(L,"__gc");
421
lua_pushcfunction(L,class_gc_event);