TOLUA_API void tolua_usertype (lua_State* L, const char* type)
{
char ctype[128] = "const ";
strncat(ctype,type,120);
/* create both metatables */
//同时创建type类型和const type类型。并且const type为type的父类
if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
mapsuper(L,type,ctype); /* 'type' is also a 'const type' */
}
static int tolua_newmetatable (lua_State* L, const char* name)
{
//创建一个table,并且在注册表中与name对应 reg[name] = mt
int r = luaL_newmetatable(L,name);
#ifdef LUA_VERSION_NUM /* only lua 5.1 */
if (r) {
lua_pushvalue(L, -1);
lua_pushstring(L, name);
//同时建立反向映射,这样就可以根据一个name对应的用户类型变量找到该变量的类名
//将类名和某一种类名进行比较,就可以判断是不是某种类型。
lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */
};
#endif
if (r)
tolua_classevents(L); /* set meta events */ //向metatable中注册各种元方法,比如:__index,__newindex,__add等等
lua_pop(L,1);
return r;
}
作用:将base设置成name的基类,并且将base的全部父类也设置成name的基类
源代码和分析:
static void mapsuper (lua_State* L, const char* name, const char* base)
{
/* push registry.super */
lua_pushstring(L,"tolua_super");//-1
lua_rawget(L,LUA_REGISTRYINDEX); /* stack: super */
luaL_getmetatable(L,name); /* stack: super mt */
lua_rawget(L,-2); /* stack: super table */
if (lua_isnil(L,-1))
{
/* create table */
lua_pop(L,1);
lua_newtable(L); /* stack: super table */
luaL_getmetatable(L,name); /* stack: super table mt */
lua_pushvalue(L,-2); /* stack: super table mt table */
lua_rawset(L,-4); /* stack: super table */
//tolua_super在 注册表中也对应一张表,表的内容为:
//table[key] = value,key是:用户类型对应的表,value是:一张表
//以name = cc.Node为例,全局表:G_Table,tolua_super对应的表:Super_Table
//ta = G_Table[name] Super_Table[ta] = tb(tb就是name在Super_Table中对应的表),它的具体数据看下面
//我们简称tb为name的父类表
}
//开始往tb中塞数据
/* set base as super class */
//先把直接父类塞进去
lua_pushstring(L,base);
lua_pushboolean(L,1);
lua_rawset(L,-3); /* stack: super table */
//再把父类的所有父类塞进去,即将父类对应的父类表中所有的数据拷贝到子类的父类表中去
/* set all super class of base as super class of name */
luaL_getmetatable(L,base); /* stack: super table base_mt */
//获取base对应的父类表,接下来就是遍历父类表吧
lua_rawget(L,-3); /* stack: super table base_table */
if (lua_istable(L,-1))
{
/* traverse base table */
lua_pushnil(L); /* first key */
while (lua_next(L,-2) != 0)
{
/* stack: ... base_table key value */
lua_pushvalue(L,-2); /* stack: ... base_table key value key */
lua_insert(L,-2); /* stack: ... base_table key key value */
lua_rawset(L,-5); /* stack: ... base_table key */
}
}
lua_pop(L,3); /* stack: */
}
作用:并且设置该lua类的父类,lname:我的理解是该lua类的模块名,name:类名, base:父类名
例子:cc.Node的表注册结构:
global_table
-cc_table
-Node_table
源码和分析:
TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col)
{
char cname[128] = "const ";
char cbase[128] = "const ";
strncat(cname,name,120);
strncat(cbase,base,120);
mapinheritance(L,name,base);//设置base表为name表的元表,继承啊!!这样才可以访问到父类的成员。还有创建tolua_ubox表。
mapinheritance(L,cname,name);
mapsuper(L,cname,cbase);//拷贝父类
mapsuper(L,name,base);
lua_pushstring(L,lname);
push_collector(L, name, col);//设置表的.collector函数
/*
luaL_getmetatable(L,name);
lua_pushstring(L,".collector");
lua_pushcfunction(L,col);
lua_rawset(L,-3);
*/
luaL_getmetatable(L,name);
//向当前的模块进行注册 如果当前的模块名是cc,lname为Node,那么cc_module_table[lname] = name_table
lua_rawset(L,-3); /* assign class metatable to module */
/* now we also need to store the collector table for the const
instances of the class */
push_collector(L, cname, col);
/*
luaL_getmetatable(L,cname);
lua_pushstring(L,".collector");
lua_pushcfunction(L,col);
lua_rawset(L,-3);
lua_pop(L,1);
*/
}
TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
{
if (name)
{
/* tolua module */
lua_pushstring(L,name);
lua_rawget(L,-2);//拿到name在当前模块表中是否进行了注册
if (!lua_istable(L,-1)) /* check if module already exists */
{
//没有注册过,new一个
lua_pop(L,1);
lua_newtable(L);
lua_pushstring(L,name);
lua_pushvalue(L,-2);
//注册到当前模块表中去
lua_rawset(L,-4); /* assing module into module */
}
}
else
{
/* global table */
//这个是全局表,会被最先放入到栈中去。因为它是所有其他根模块的进行注册的地方
lua_pushvalue(L,LUA_GLOBALSINDEX);
}
.......
lua_pop(L,1); /* pop module */
}
作用:顾名思义,开始一个模块
实现方式:将name对应的模块表放入到栈顶。
源码和分析:(这个貌似不需要解释吧,很简单)
TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
{
if (name)
{
lua_pushstring(L,name);
lua_rawget(L,-2);
}
else
lua_pushvalue(L,LUA_GLOBALSINDEX);
}
//作用:判断在lua栈中的lo位置的类型是不是type(不要忘了父类哟!!)。
//type:要比较的类型名
int lua_isusertype (lua_State* L, int lo, const char* type)
{
if (!lua_isuserdata(L,lo)) {
if (!push_table_instance(L, lo)) {
return 0;
};
};
{
/* check if it is of the same type */
int r;
const char *tn;
//获取到lo位置的userdata的metatable表
if (lua_getmetatable(L,lo)) /* if metatable? */
{
//当创建类的时候,会进行双向映射,所以可以根据table获取类名
lua_rawget(L,LUA_REGISTRYINDEX); /* get registry[mt] */
tn = lua_tostring(L,-1);
r = tn && (strcmp(tn,type) == 0);//如果对应的类名就是type,那么loc位置的userdata就是对应type类型
lua_pop(L, 1);
if (r)
return 1;
else
{
//不要忘了所有的父类哟!!还记得父类是怎么实现的么,详细请参考:tolua_map.mapsuper()
/* check if it is a specialized class */
lua_pushstring(L,"tolua_super");
lua_rawget(L,LUA_REGISTRYINDEX); /* get super */
lua_getmetatable(L,lo);
lua_rawget(L,-2); /* get super[mt] */
if (lua_istable(L,-1))
{
int b;
lua_pushstring(L,type);
lua_rawget(L,-2); /* get super[mt][type] */
b = lua_toboolean(L,-1);
lua_pop(L,3);
if (b)
return 1;
}
}
}
}
return 0;
}
static void mapinheritance (lua_State* L, const char* name, const char* base)
{
/* set metatable inheritance */
luaL_getmetatable(L,name);
if (base && *base)
luaL_getmetatable(L,base);
else {
if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */
lua_pop(L, 2);
return;
};
luaL_getmetatable(L,"tolua_commonclass");
};
set_ubox(L);
lua_setmetatable(L,-2);
lua_pop(L,1);
}
static void set_ubox(lua_State* L) {
/* mt basemt */
if (!lua_isnil(L, -1)) {
lua_pushstring(L, "tolua_ubox");
lua_rawget(L,-2);//获取base表中的tolua_ubox值
} else {
lua_pushnil(L);
};
/* mt basemt base_ubox */
if (!lua_isnil(L,-1)) {
//得到父类tolua_ubox表
lua_pushstring(L, "tolua_ubox");
lua_insert(L, -2);
/* mt basemt key ubox */
lua_rawset(L,-4);
/* (mt with ubox) basemt */
} else {
/* mt basemt nil */
//如果不存在base或者base中没有tolua_ubox,那么为子类创建一个弱引用的tolua_ubox表
lua_pop(L, 1);
lua_pushstring(L,"tolua_ubox");
lua_newtable(L);
/* make weak value metatable for ubox table to allow userdata to be
garbage-collected */
lua_newtable(L);
lua_pushliteral(L, "__mode");
lua_pushliteral(L, "v");//值为弱引用
lua_rawset(L, -3); /* stack: string ubox mt */
lua_setmetatable(L, -2); /* stack:mt basemt string ubox */
lua_rawset(L,-4);
};
};