Skip to content

Commit 5a997d1

Browse files
committed
The Lua Class is not a meta table now. It is a normal table, has a key named ".isclass", and a meta table has been set to it.
To judge a Lua Class's type, must use it's meta table. All the origin keys (in c/c++) were stored in Lua Class's meta table (and it's "parents's" meta table) . If a origin key was overrided in Lua, it was backup in a table named ".backup". This backup table is a key of the meta table. ONLY a origin key was overrided, you can use "tolua. getcfunction(class or object, key_name)" to return it, otherwise, the function return nil.
1 parent 694f5b9 commit 5a997d1

3 files changed

Lines changed: 205 additions & 21 deletions

File tree

lua/tolua/tolua_event.c

Lines changed: 120 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,40 @@ static int module_newindex_event (lua_State* L)
130130
return 0;
131131
}
132132

133+
static int class_table_get_index (lua_State* L)
134+
{
135+
// stack: obj key ... obj
136+
137+
while (lua_getmetatable(L,-1)) { /* stack: obj key obj mt */
138+
lua_remove(L,-2); /* stack: ... mt */
139+
140+
lua_pushvalue(L,2); /* stack: ... mt key */
141+
lua_rawget(L,-2); /* stack: ... mt value */
142+
if (!lua_isnil(L,-1)) {
143+
return 1;
144+
} else {
145+
lua_pop(L,1);
146+
}
147+
148+
/* try C/C++ variable */
149+
lua_pushstring(L,".get");
150+
lua_rawget(L,-2); /* stack: obj key ... mt tget */
151+
if (lua_istable(L,-1)) {
152+
lua_pushvalue(L,2); /* stack: obj key ... mt tget key */
153+
lua_rawget(L,-2); /* stack: obj key ... mt tget value */
154+
if (lua_iscfunction(L,-1)) {
155+
lua_call(L,0,1);
156+
return 1;
157+
} else if (lua_istable(L,-1)) {
158+
return 1;
159+
}
160+
lua_pop(L, 2);
161+
}
162+
}
163+
lua_pushnil(L);
164+
return 1;
165+
}
166+
133167
/* Class index function
134168
* If the object is a userdata (ie, an object), it searches the field in
135169
* the alternative table stored in the corresponding "ubox" table.
@@ -227,13 +261,65 @@ static int class_index_event (lua_State* L)
227261
}
228262
else if (t== LUA_TTABLE)
229263
{
230-
module_index_event(L);
264+
lua_pushvalue(L,1);
265+
class_table_get_index(L);
231266
return 1;
232267
}
233268
lua_pushnil(L);
234269
return 1;
235270
}
236271

272+
static int class_backup_before_newindex (lua_State* L)
273+
{
274+
/* stack: t k v */
275+
int m;
276+
277+
lua_pushvalue(L, 1);
278+
m = lua_getmetatable(L,-1); /* stack: t k v t mt */
279+
while (m>0 && lua_istable(L,-1)) {
280+
lua_remove(L, -2); /* stack: t k v mt */
281+
//Check if key had been backup
282+
lua_pushstring(L, ".backup");
283+
lua_rawget(L, -2); /* stack: t k v mt mt[".backup"] */
284+
if (!lua_isnil(L, -1)) {
285+
lua_pushvalue(L, 2); /* stack: t k v mt mt[".backup"] k */
286+
lua_rawget(L, -2);
287+
if (!lua_isnil(L, -1)) {
288+
// key had been backup
289+
return 0;
290+
}
291+
lua_pop(L, 1);
292+
}
293+
lua_pop(L, 1); /* stack: t k v mt */
294+
295+
//Check if key is exist in mt
296+
lua_pushvalue(L, 2);
297+
lua_rawget(L, -2); /* stack: t k v mt mt[k] */
298+
if (!lua_isnil(L, -1)) {
299+
lua_pushvalue(L, -2); /* stack: t k v mt mt[k] mt */
300+
lua_pushstring(L, ".backup");
301+
lua_rawget(L, -2); /* stack: t k v mt mt[k] mt mt[".backup"] */
302+
if (lua_isnil(L, -1)) {
303+
//Create a table and set to mt[".backup"]
304+
lua_pop(L, 1); /* stack: t k v mt mt[k] mt */
305+
lua_pushstring(L, ".backup");
306+
lua_newtable(L);
307+
lua_rawset(L, -3);
308+
lua_pushstring(L, ".backup");
309+
lua_rawget(L, -2); /* stack: t k v mt mt[k] mt mt[".backup"] */
310+
}
311+
lua_pushvalue(L, 2); /* stack: t k v mt mt[k] mt mt[".backup"] k */
312+
lua_pushvalue(L, -4); /* stack: t k v mt mt[k] mt mt[".backup"] k mt[k] */
313+
lua_rawset(L, -3);
314+
return 0;
315+
}
316+
lua_pop(L, 1); /* stack: t k v mt */
317+
m = lua_getmetatable(L,-1); /* stack: t k v mt base_mt */
318+
}
319+
320+
return 0;
321+
}
322+
237323
/* Newindex function
238324
* It first searches for a C/C++ varaible to be set.
239325
* Then, it either stores it in the alternative ubox table (in the case it is
@@ -292,24 +378,46 @@ static int class_newindex_event (lua_State* L)
292378
}
293379
else if (t== LUA_TTABLE)
294380
{
295-
module_newindex_event(L);
381+
lua_getmetatable(L,1); /* stack: t k v mt */
382+
lua_pushstring(L,".set");
383+
lua_rawget(L,-2); /* stack: t k v mt tset */
384+
if (lua_istable(L,-1)) {
385+
lua_pushvalue(L,2); /* stack: t k v mt tset k */
386+
lua_rawget(L,-2);
387+
if (lua_iscfunction(L,-1)) { /* ... func */
388+
lua_pushvalue(L,1); /* ... func t */
389+
lua_pushvalue(L,3); /* ... func t v */
390+
lua_call(L,2,0);
391+
return 0;
392+
}
393+
}
394+
lua_settop(L,3);
395+
class_backup_before_newindex(L);
396+
lua_settop(L,3);
397+
lua_getmetatable(L,1); /* stack: t k v mt */
398+
lua_replace(L, 1); /* stack: mt k v */
399+
lua_rawset(L,1);
296400
}
297401
return 0;
298402
}
299403

300404
static int class_call_event(lua_State* L) {
301405

302406
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-
};
407+
//class is not a metatable now, so must get it's metatable to access ".call" function. 2014.6.5 by SunLightJuly
408+
if (lua_getmetatable(L, 1)) {
409+
lua_replace(L, 1);
410+
lua_pushstring(L, ".call");
411+
lua_rawget(L, 1);
412+
if (lua_isfunction(L, -1)) {
413+
414+
lua_insert(L, 1);
415+
lua_call(L, lua_gettop(L)-1, 1);
416+
417+
return 1;
418+
}
419+
}
420+
}
313421
tolua_error(L,"Attempt to call a non-callable object.",NULL);
314422
return 0;
315423
};

lua/tolua/tolua_is.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,22 @@ static int lua_isusertable (lua_State* L, int lo, const char* type)
120120
{
121121
int r = 0;
122122
if (lo < 0) lo = lua_gettop(L)+lo+1;
123-
lua_pushvalue(L,lo);
123+
lua_pushvalue(L, lo); // stack: ... table
124+
125+
// A class table must use metatable to get it's type now. 2014.6.5 by SunLightJuly
126+
if (lua_istable(L, -1)) {
127+
lua_pushliteral(L, ".isclass");
128+
lua_rawget(L, -2); // stack: ... table class_flag
129+
if (!lua_isnil(L, -1)) {
130+
lua_pop(L, 1); // stack: ... table
131+
if (lua_getmetatable(L, -1)) { // stack: ... table mt
132+
lua_remove(L, -2); // stack: ... mt
133+
}
134+
} else {
135+
lua_pop(L, 1); // stack: ... table
136+
}
137+
}
138+
124139
lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[t] */
125140
if (lua_isstring(L,-1))
126141
{

lua/tolua/tolua_map.c

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,44 @@ static int tolua_bnd_getpeer(lua_State* L) {
292292
};
293293
#endif
294294

295+
/* Get the index which have been override
296+
2014.6.5 by SunLightJuly
297+
*/
298+
static int tolua_bnd_getcfunction(lua_State* L) {
299+
if (!lua_isstring(L, 2)) {
300+
lua_pushstring(L, "Invalid argument #2 to getcfunction: string expected.");
301+
lua_error(L);
302+
}
303+
304+
if (!lua_getmetatable(L, 1)) {
305+
lua_pushstring(L, "Invalid argument #1 to getcfunction: class or object expected.");
306+
lua_error(L);
307+
}
308+
309+
/* stack: class key mt */
310+
while (1) {
311+
lua_pushstring(L, ".backup");
312+
lua_rawget(L, -2); /* stack: class key mt mt[".backup"] */
313+
if (!lua_isnil(L, -1)) {
314+
lua_pushvalue(L, 2); /* stack: class key mt mt[".backup"] key */
315+
lua_rawget(L, -2);
316+
if (!lua_isnil(L, -1)) { // key had been found
317+
return 1;
318+
}
319+
lua_pop(L, 1);
320+
}
321+
lua_pop(L, 1); /* stack: class key mt */
322+
323+
if (!lua_getmetatable(L, -1)) {
324+
break;
325+
}
326+
/* stack: class key mt base_mt */
327+
lua_remove(L, -2); /* stack: class key base_mt */
328+
}
329+
330+
return 0;
331+
}
332+
295333
/* static int class_gc_event (lua_State* L); */
296334

297335
TOLUA_API void tolua_open (lua_State* L)
@@ -372,6 +410,7 @@ TOLUA_API void tolua_open (lua_State* L)
372410
tolua_function(L, "setpeer", tolua_bnd_setpeer);
373411
tolua_function(L, "getpeer", tolua_bnd_getpeer);
374412
#endif
413+
tolua_function(L,"getcfunction", tolua_bnd_getcfunction);
375414

376415
tolua_endmodule(L);
377416
tolua_endmodule(L);
@@ -442,13 +481,27 @@ TOLUA_API void tolua_usertype (lua_State* L, const char* type)
442481
*/
443482
TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
444483
{
445-
if (name)
446-
{
447-
lua_pushstring(L,name);
448-
lua_rawget(L,-2);
449-
}
450-
else
484+
if (name) { // ... module
485+
//---- now module[name] is a table, get it's metatable to store keys
486+
// get module[name]
487+
lua_pushstring(L,name); // ... module name
488+
lua_rawget(L,-2); // ... module module[name]
489+
// Is module[name] a class table?
490+
lua_pushliteral(L, ".isclass");
491+
lua_rawget(L, -2); // stack: ... module module[name] class_flag
492+
if (lua_isnil(L, -1)) {
493+
lua_pop(L, 1); // stack: ... module module[name]
494+
return; // not a class table, use origin table
495+
}
496+
lua_pop(L, 1); // stack: ... module class_table
497+
// get metatable
498+
if (lua_getmetatable(L, -1)) { // ... module class_table mt
499+
lua_remove(L, -2); // ... module mt
500+
}
501+
//---- by SunLightJuly, 2014.6.5
502+
} else {
451503
lua_pushvalue(L,LUA_GLOBALSINDEX);
504+
}
452505
}
453506

454507
/* End module
@@ -579,8 +632,16 @@ TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name,
579632
lua_rawset(L,-3);
580633
*/
581634

582-
luaL_getmetatable(L,name);
583-
lua_rawset(L,-3); /* assign class metatable to module */
635+
//---- create a new class table, set it's metatable, and assign it to module
636+
lua_newtable(L); // stack: module lname table
637+
luaL_getmetatable(L,name); // stack: module lname table mt
638+
lua_setmetatable(L, -2); // stack: module lname table
639+
//Use a key named ".isclass" to be a flag of class_table
640+
lua_pushliteral(L, ".isclass");
641+
lua_pushboolean(L, 1);
642+
lua_rawset(L, -3); // stack: module lname table
643+
lua_rawset(L, -3); // stack: module
644+
//---- by SunLightJuly, 2014.6.5
584645

585646
/* now we also need to store the collector table for the const
586647
instances of the class */

0 commit comments

Comments
 (0)